我有一个实体(Layer
),用于映射其他实体(Member
)的列表。此列表可能没有条目/ null
。然而,当我查询实体时,我从数据库中收到NOT NULL check constraint
错误。
它似乎已连接到NamedQueries
,因为如果我按id
查询,我可以从数据库中读取实体。
@Entity
@NamedQueries({
@NamedQuery(name="getChildLayers",-
query = "SELECT la
FROM Layer la
WHERE la.parent = :parent AND la.deletedDate IS NULL")})
public class Layer extends CommonModel {
/*... other field */
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Layer.class, optional = true)
private Layer parent;
@ManyToMany(fetch = FetchType.LAZY, targetEntity = MyUser.class)
private List<MyUser> members;
public List<MyUser> getMembers() {
return members;
}
public void setMembers(List<MyUser> members) {
this.members = members;
}
/*... other getters and setters */
}
我收到此错误:integrity constraint violation: NOT NULL check constraint; SYS_CT_10298 table: LAYER_MYUSER column: MEMBERS_ID
我可以创建条目。
当我运行我的测试时,所有测试都失败,读取实体(但创建工作)。如果我在创建方法中添加以下行:
layer.setMembers(new ArrayList<MyUser>());
然后测试成员交替工作的方法(意思是,我可以通过在列表中添加和删除元素来创建Layer
并更改其members
。)
在我看来,只要Member
没有Layer
,就从数据库中读取实体会失败。
我确实尝试将@JoinColumn(nullable=true)
添加到字段中,但它没有改变任何内容。
我导入了javax.persistence
个类。
关于如何访问变量(LayerService
)
// this method works as expected
public Layer getById(Long id) {
Session s = sessionFactory.getCurrentSession();
return (Layer)s.get(Layer.class, id);
}
// this does not.
public List<Layer> getChildren(Layer layer) {
Query childrenQuery = sessionFactory.getCurrentSession().getNamedQuery("getChildLayers");
childrenQuery.setParameter("parent", layer);
return (List<Layer>) childrenQuery.list();
}
Jason Cs回答后代码改变了:
Layer
...
private final List<OCWUser> members = new ArrayList<>();
...
public void setMembers(List<OCWUser> members) {
this.members.clear();
this.members.addAll(members);
}
问题仍然存在。
答案 0 :(得分:4)
它可以这么简单。我忘了添加@JoinTable
@JoinTable(name = "LAYER_USER", joinColumns = @JoinColumn(nullable = true))
答案 1 :(得分:2)
要注意的一件重要事情是,除非您在致电this.members
之前知道自己正在执行此操作,否则不应将setMembers
替换为persist()
中的其他列表。相反,您需要清除this.members
,然后将所有指定的元素添加到其中。原因是Hibernate可以并且将在[de]序列化实体时使用自己的代理/检测集合类,并在覆盖集合类时将其吹掉。您应将members
声明为final
并始终将其初始化为非空的空List
。
参见例如(3.6但仍然相关):http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/collections.html#collections-persistent,特别是:
请注意例7.2中的“使用@OneToMany和。的集合映射” @JoinColumn“实例变量部分用一个初始化 HashSet的实例。这是初始化集合的最佳方式 新实例化(非持久)实例的有价值属性。 当你使实例持久化时,通过调用persist(),Hibernate 实际上会用Hibernate自己的实例替换HashSet Set的实现。
只要您以这种方式搞乱收集字段,就会发生任何奇怪的事情。
<小时/> 此外,一般情况下,您希望在以这种方式访问集合时要小心说明不变量,因为很容易,例如,创建两个内部引用相同集合的Layers
,以便在一个集合上执行操作影响另一个,或者传入集合的外部操作会影响图层,例如以下代码可能不像您希望的那样:
List<MyUser> u = new ArrayList<MyUser>();
Layer a = new Layer();
Layer b = new Layer();
u.add(...);
a.setMembers(u);
b.setMembers(u);
u.clear();
此外,当你persist()
其中一个层,并且Hibernate用自己的集合类覆盖该字段时,行为会随着对象不再引用相同的集合而改变:
// not only did u.clear() [possibly undesirably] affect a and b above, but:
session.persist(a);
u.add(...); // ... now it only affects b.