EntityManager.find 无法找到实体,但使用 Criteria API 可以
我在 Java EE 6 中遇到了一个相当奇怪的情况,其中使用 JPA EntityManager 的 find
方法以及实体的主 id 返回 null,但使用 Criteria API 选择具有该 id 的所有实体效果很好。
这是我用于 find
的代码:
// Always returns null, even for records I know for sure are in there.
user = em.find(User.class, userId);
...这是我与 Criteria 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
返回 null 但 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;
}
...
}
I've encountered a rather odd case in Java EE 6 where using the JPA EntityManager's find
method along with an entity's primary id returns null, but using the Criteria API to select all entities with that id works fine.
Here is the code I'm using for find
:
// Always returns null, even for records I know for sure are in there.
user = em.find(User.class, userId);
...and here's the code I'm using with the Criteria 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();
Any idea why find
returns null but Criteria finds the User? I tried these two alternate methods in the exact same spot in the program.
Here are the relevant portions of the User entity:
@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;
}
...
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
仔细检查您是否在以下代码片段中传递了
Long
:如果这没有帮助,请激活 SQL 日志记录以查看发生的情况并比较两种情况下的行为。
Double check that you are passing a
Long
in the following snippet:If this doesn't help, activate SQL logging to see what is happening and compare the behavior in both cases.
原因之一可能是“id”字段未正确标记为用户实体的 ID。
One reason could be that the "id" field has not been correctly marked as the id for the User entity.
作为健全性检查调试您的代码,在执行查找之前花一些时间自己在数据库上运行手动查询,以确保存在具有您期望的 id 的适当的用户记录。
如果它不在数据库中,请确保实体管理器已被刷新或当前事务已被提交。
例如,如果您使用 Hibernate 作为提供程序,则该对象可能仅“保留”在缓存中,而更改实际上并未推送到数据库。因此,通过 Hibernate 实现的标准将检索该对象,但实体管理器查找将无法找到该对象。
As a sanity check debug your code, taking the time before executing the find to run a manual query on the database yourself to ensure that an appropriate User record is present with the id you expect.
If it's not in the database, ensure that the entity manager has been flushed or the current transaction has been committed.
For instance, if you are using Hibernate as the provider, it is possible that the object is "persisted" merely in cache and the changes have not actually been pushed to the database. Accordingly, the criteria going through Hibernate's implementation will retrieve the object, but the entity manager find will not be able to locate the object.
我发现了问题所在。这是由于数据库中的一个字段为
null
,而这是不应该允许的。这是由于我手动编辑的。当我向该字段添加值后,问题就消失了。I figured out the problem. It was due to a field in the database being
null
where it should not have been permitted. This was due to me editing it by hand. After I added a value to that field, the problem went away.您使用什么提供商?
您在哪里执行此查找,是在事务内还是事务外?您在发现之前是否冲洗并清理了 EM?
使用 EclipseLink 作为提供程序以及我自己的类似模型,我无法重现这一点。
假设您的提供商可以记录 SQL,您是否看到 SQL 在查找时进入数据库? SQL 是什么样的,它在 SQL Plus 等中是否正确执行......
What provider are you using?
Where are you executing this find, in or out of a transaction? Are you flushing and clearing the EM prior to the find?
Using EclipseLink as a provider, and my own similar model, I am not able to reproduce this.
Assuming your provider can log SQL, are you seeing SQL going to the DB on the find? What does the SQL look like, and does it execute properly in SQL Plus etc...
我确认解决方案。同样的事情也发生在我身上。我将列标记为
NOT NULL
,然后在我的应用程序中进行测试期间,我关闭了数据库中两个列(外键)的限制,但没有更改 (Optional = false
code>) 我的实体类中@ManyToOne
关系的属性。删除属性后,模型与数据库一致,一切开始正常工作。奇怪的是环境不会产生某种警告或异常。
I confirm the solution. The same thing happened to me. I had collumns marked as
NOT NULL
, then during test in my app I switched the limitation off in the database for two collumns (foreign keys), however not changing the (optional = false
) attribute of@ManyToOne
relationship in my entity class. After deleting the attribute, so the model was consistent with the database, everything started to work fine.Strange that the environment does not produce a warning or exception of some kind.