我的模型中有一个集合,其中包含一组我的根域对象的"先前版本".因此,以前的版本是"不可变的",我们永远不会想要更新它们,只希望在它们出现时添加过去的版本."版本化"的域对象也相当复杂,导致需要大量数据库访问才能检索.
当我有这些对象之一的新版本时,我想将其与其他对象保存,而不加载整个集合.高级常见问题解答有一些建议:
当我只想添加或删除元素时,为什么Hibernate总是初始化集合?
遗憾的是,集合API定义了方法返回值,这些值只能通过命中数据库来计算.这有三个例外:Hibernate可以添加到a
<bag>,<idbag>或者<list>在inverse="true"没有初始化集合的情况下声明; 返回值必须始终为true.如果要避免额外的数据库流量(即在性能关键代码中),请重构模型以仅使用多对一关联.这几乎总是可行的.然后使用查询代替集合访问.
我是所有这一切的新手,并不是100%肯定如何重构你的模型只使用多对一的关联.任何人都可以给我一个例子,指出我的教程,以便我可以了解这将如何解决我的问题?
Art*_*ald 11
如果你有一个List或基于Set的集合,并且在你的集合中添加了一个新对象,Hibernate将始终访问数据库,因为它在保存或更新之前使用equals实现比较逐个对象 - 使用Set时 - 或通过比较使用List时的索引列.由于Set和List语义,因此需要此行为.因此,无论您拥有大量记录,应用程序的性能都会显着降低.
解决此问题的一些解决方法
1º转换模式使用封装的Bag集合以及作为属性公开的所需Set或List
@Entity
public class One {
private Collection<Many> manyCollection = new ArrayList<Many>();
@Transient
public Set<Many> getManyCollectionAsSet() { return new HashSet<Many>(manyCollection); }
public void setManyCollectionAsSet(Set<Many> manySet) { manyCollection = new ArrayList<Many>(manySet); }
/**
* Keep in mind that, unlike Hibernate, JPA specification does not allow private visibility. You should use public or protected instead
*/
@OneToMany(cascade=ALL)
private Collection<Many> getManyCollection() { return manyCollection; }
private void setManyCollection(Collection<Many> manyCollection) { this.manyCollection = manyCollection; }
}
Run Code Online (Sandbox Code Playgroud)
2º使用ManyToOne而不是OneToMany
@Entity
public class One {
/**
* Neither cascade nor reference
*/
}
@Entity
public class Many {
private One one;
@ManyToOne(cascade=ALL)
public One getOne() { return one; }
public void setOne(One one) { this.one = one }
}
Run Code Online (Sandbox Code Playgroud)
3º缓存 - 应用时,根据您的要求,您的配置可能会增加或降低应用程序的性能.看到这里
4° SQL约束 - 如果希望集合的行为类似于Set,则可以使用SQL约束,该约束可应用于列或列集.看到这里
我通常这样做的方法是将集合定义为"反向".
这大致意味着:1-N关联的主要定义是在"N"端完成的.如果要在集合中添加内容,则可以更改详细数据的关联对象.
一个小的XML示例:
<class name="common.hibernate.Person" table="person">
<id name="id" type="long" column="PERSON_ID">
<generator class="assigned"/>
</id>
<property name="name"/>
<bag name="addresses" inverse="true">
<key column="PERSON_ID"/>
<one-to-many class="common.hibernate.Address"/>
</bag>
</class>
<class name="common.hibernate.Address" table="ADDRESS">
<id name="id" column="ADDRESS_ID"/>
<property name="street"/>
<many-to-one name="person" column="PERSON_ID"/>
</class>
Run Code Online (Sandbox Code Playgroud)
然后更新只在地址中完成:
Address a = ...;
a.setPerson(me);
a.setStreet("abc");
Session s = ...;
s.save(a);
Run Code Online (Sandbox Code Playgroud)
完成.你甚至没有碰过这个系列.将其视为只读,这对于使用HQL进行查询以及迭代和显示它可能非常实用.
| 归档时间: |
|
| 查看次数: |
14317 次 |
| 最近记录: |