2010-07-08 13 views
7

我在Java EE 6中遇到了一個相當奇怪的例子,其中使用JPA EntityManager的find方法以及實體的主ID返回null,但使用Criteria API來選擇具有該ID的所有實體工作正常。EntityManager.find無法找到實體,但使用Criteria API確實

這裏是我使用find代碼:

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

...這是我使用與標準API代碼:

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(); 

任何想法,爲什麼find回報空但Criteria找到用戶?我在程序中完全相同的地方嘗試了這兩種替代方法。

下面是用戶實體的相關部分:

@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

不知道這是否有所作爲,但在代碼中是userId a Long還是Integer? – 2010-07-08 16:41:12

+0

這是一個長,我仔細檢查。 – cdmckay 2010-07-08 18:18:12

+0

我剛剛遇到了這個問題與休眠4.1.8.Final – molholm 2014-03-18 09:22:30

回答

11

我想出了這個問題。這是由於數據庫中的一個字段爲null,因此它不應該被允許。這是由於我手工編輯它。在向該字段添加值後,問題就消失了。

+2

您可能需要爲該列強制執行NOT NULL以備將來使用。 – ChuongPham 2011-04-26 13:29:46

+0

歡呼聲分享,拯救了我的一天 – MarianP 2015-06-23 16:26:10

+0

@ChuongPham:100%同意。這不是我的數據庫,但它教會了使用約束來強制數據完整性的價值;) – cdmckay 2015-06-23 20:35:37

0

其中一個原因可能是因爲「ID」字段沒有被正確標記爲id爲用戶實體。

3

你在使用什麼提供商?

你在哪裏執行這個查找事務?您是否在查找之前沖洗並清理EM?

使用EclipseLink作爲提供程序,以及我自己的類似模型,我無法重現此操作。

假設您的提供程序可以記錄SQL,您是否看到SQL發現數據庫? SQL看起來像什麼,並且它在SQL Plus等中是否正確執行......

+0

我應該在查找之前刷新EM?我使用Hibernate作爲我的提供者。 – cdmckay 2010-07-08 18:19:07

+0

我正在'@ Stateless' EJB中運行它。 EM用'@PersistanceContext(unitName =「xxx_persistence」)'裝飾。我將參考SQL日誌,看看我能找到什麼。 – cdmckay 2010-07-08 18:21:16

+0

好吧,我檢查了SQL,很驚訝地看到兩個查詢之間的區別:「查找」版本正在做十億個連接,而「標準」查詢只是從用戶表中獲取。其他人寫了實體文件,所以我不得不通過這些來找出是什麼原因造成的。 – cdmckay 2010-07-08 20:11:19

0

作爲一個健全檢查調試你的代碼,在執行查找之前花時間自己對數據庫運行手動查詢以確保一個適當的用戶記錄與您所期望的ID一同出現。

如果它不在數據庫中,請確保已刷新實體管理器或已提交當前事務。例如,如果您使用Hibernate作爲提供程序,則該對象可能僅在緩存中「保留」,並且更改實際上未被推送到數據庫。因此,通過Hibernate實現的標準將檢索該對象,但實體管理器查找將無法找到該對象。

+0

這是一個很好的建議,但我知道它沒有被緩存,因爲我甚至可以在啓動應用程序之前查看數據庫。 – cdmckay 2010-07-08 20:12:57

1

仔細檢查您在下面的代碼段傳遞Long

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

如果這沒有幫助,啓動SQL日誌記錄,看看發生什麼事,在這兩種情況下進行比較的行爲。

+0

我調試並檢查它確實是一個長。 – cdmckay 2010-07-08 20:12:11

+0

@cdmckay:我在你身邊運行你的代碼,我無法重現(如預期的那樣)。使用Hibernate EM 3.5.3-Final進行測試。 – 2010-07-08 20:58:02

+0

是的,我認爲這與用戶實體註釋的方式有關。 – cdmckay 2010-07-09 04:55:42

3

我確認解決方案。這樣的事情我也經歷過。我有列標記爲NOT NULL,然後在我的應用程序測試期間,我關閉在數據庫中的限制關閉兩個列(外鍵),但不改變我的實體類中@ManyToOne關係的(optional = false)屬性。刪除屬性後,模型與數據庫一致,一切開始正常工作。 奇怪的是,環境不會產生某種警告或例外。

相關問題