2010-07-08 37 views
7

Tôi đã gặp phải một trường hợp khá kỳ lạ trong Java EE 6 khi sử dụng phương thức find của JPA EntityManager cùng với id chính của thực thể trả về null, nhưng sử dụng tiêu chí API để chọn tất cả các thực thể có id đó hoạt động tốt.EntityManager.find không thể tìm thấy thực thể, nhưng sử dụng API tiêu chí không

Đây là mã Tôi đang sử dụng cho find:

// Always returns null, even for records I know for sure are in there. 
user = em.find(User.class, userId); 

... và đây là đoạn code tôi đang sử dụng với các API Tiêu chí:

CriteriaBuilder builder = em.getCriteriaBuilder(); 
CriteriaQuery<User> criteria = builder.createQuery(User.class); 
Root<User> u = criteria.from(User.class); 
TypedQuery<User> query = em.createQuery(
    criteria.select(u).where(builder.equal(u.get("id"), userId))); 
user = query.getSingleResult(); 

Bất cứ ý tưởng tại sao find lợi nhuận null nhưng tiêu chí tìm thấy người dùng? Tôi đã thử hai phương pháp thay thế này trong cùng một vị trí chính xác trong chương trình.

Sau đây là các phần có liên quan của các tổ chức tài:

@Entity 
@Table(name = "USERS") 
@Access(AccessType.PROPERTY) 
public class User implements Serializable { 
    ... 
    private Long id; 
    ... 
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id_generator") 
    @SequenceGenerator(name = "user_id_generator", sequenceName = "user_sequence", allocationSize = 1) 
    @Column(name="id") 
    public Long getId() { 
     return this.id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 
    ... 
} 
+0

Bạn không chắc chắn điều này có tạo nên sự khác biệt hay không, nhưng có phải userId là Dài hoặc có thể là Số nguyên trong mã của bạn không? –

+0

Đó là một Long, tôi kiểm tra lại điều đó. – cdmckay

+0

Tôi chỉ gặp vấn đề này với Hibernate 4.1.8.Final – molholm

Trả lời

11

Tôi đã tìm ra sự cố. Đó là do một trường trong cơ sở dữ liệu là null nơi mà nó không được phép. Điều này là do tôi chỉnh sửa nó bằng tay. Sau khi tôi thêm giá trị vào trường đó, sự cố đã biến mất.

+2

Bạn có thể muốn thực thi NOT NULL cho cột đó để bảo vệ tương lai. – ChuongPham

+0

cổ vũ để chia sẻ, đã lưu ngày của tôi – MarianP

+0

@ChuongPham: 100% đồng ý. Đây là cơ sở dữ liệu của tôi, nhưng nó đã dạy tôi giá trị của việc sử dụng các ràng buộc để thực thi toàn vẹn dữ liệu;) – cdmckay

0

Một lý do có thể là lĩnh vực "id" đã không được đánh dấu một cách chính xác như id cho đối tượng người dùng.

3

Bạn đang sử dụng nhà cung cấp nào?

Bạn đang thực hiện tìm kiếm này ở đâu, trong hoặc ngoài giao dịch? Bạn đang xả nước và xóa EM trước khi tìm?

Sử dụng EclipseLink làm nhà cung cấp và mô hình tương tự của riêng tôi, tôi không thể tái tạo điều này.

Giả sử nhà cung cấp của bạn có thể đăng nhập SQL, bạn có nhìn thấy SQL đi tới DB trên tìm không? SQL trông như thế nào, và nó có thực hiện đúng trong SQL Plus hay không ...

+0

Tôi nên xả bỏ EM trước khi tìm thấy? Tôi đang sử dụng Hibernate làm nhà cung cấp của mình. – cdmckay

+0

Tôi đang chạy nó trong một EJB '@ Stateless'. EM được trang trí bằng '@PersistanceContext (unitName =" xxx_persistence ")'. Tôi sẽ tham khảo các bản ghi SQL và xem những gì tôi có thể tìm thấy. – cdmckay

+0

Ok tôi đã kiểm tra SQL và rất ngạc nhiên khi thấy sự khác biệt giữa hai truy vấn: phiên bản "tìm" đang thực hiện một tỷ lần kết nối trong khi truy vấn "tiêu chí" chỉ lấy từ bảng người dùng. Một người khác đã viết các tập tin thực thể vì vậy tôi sẽ phải đào sâu những người đó để tìm ra nguyên nhân gây ra điều này. – cdmckay

0

Khi kiểm tra sanity gỡ lỗi mã của bạn, hãy dành thời gian trước khi thực hiện tìm để chạy truy vấn thủ công trên cơ sở dữ liệu để đảm bảo rằng một hồ sơ Người dùng thích hợp có mặt với id bạn mong đợi.

Nếu không có trong cơ sở dữ liệu, hãy đảm bảo rằng trình quản lý đối tượng đã bị xóa hoặc giao dịch hiện tại đã được thực hiện.

Ví dụ, nếu bạn đang sử dụng Hibernate với tư cách nhà cung cấp, có thể đối tượng được "lưu giữ" chỉ trong bộ đệm và các thay đổi chưa thực sự được đẩy vào cơ sở dữ liệu. Theo đó, các tiêu chí đi qua việc thực hiện Hibernate sẽ lấy ra đối tượng, nhưng trình quản lý thực thể tìm thấy sẽ không thể định vị đối tượng.

+0

Đây là một gợi ý tốt nhưng tôi biết rằng nó không được lưu trữ bởi vì tôi có thể xem xét trong cơ sở dữ liệu trước khi tôi bắt đầu lên ứng dụng. – cdmckay

1

Kiểm tra lại rằng bạn đang đi qua một Long trong đoạn mã sau:

// Always returns null, even for records I know for sure are in there. 
user = em.find(User.class, userId); 

Nếu điều này không giúp đỡ, kích hoạt SQL khai thác gỗ để xem những gì đang xảy ra và so sánh các hành vi trong cả hai trường hợp.

+0

Tôi đã sửa lỗi và kiểm tra xem nó có thực sự là Long hay không. – cdmckay

+0

@cdmckay: Tôi đã chạy mã của bạn ở bên cạnh tôi và tôi không thể tái tạo (như dự kiến ​​là trung thực). Thử nghiệm với Hibernate EM 3.5.3-Final. –

+0

Vâng, tôi nghĩ rằng nó đã làm với cách thực thể người dùng được chú thích. – cdmckay

3

Tôi xác nhận giải pháp. Điều tương tự cũng xảy ra với tôi.Tôi đã có các collumn được đánh dấu là NOT NULL, sau đó trong quá trình thử nghiệm trong ứng dụng của tôi, tôi đã tắt giới hạn trong cơ sở dữ liệu cho hai collumns (khóa ngoài), tuy nhiên không thay đổi thuộc tính (optional = false) của mối quan hệ @ManyToOne trong lớp thực thể của tôi. Sau khi xóa thuộc tính, vì vậy mô hình phù hợp với cơ sở dữ liệu, mọi thứ bắt đầu hoạt động tốt. Lạ lẫm rằng môi trường không tạo ra cảnh báo hoặc ngoại lệ của một số loại.

Các vấn đề liên quan