Hibernate - 如何在不加载整个Collection的情况下持久保存Collection中的新项

20 refactoring hibernate

我的模型中有一个集合,其中包含一组我的根域对象的"先前版本".因此,以前的版本是"不可变的",我们永远不会想要更新它们,只希望在它们出现时添加过去的版本."版本化"的域对象也相当复杂,导致需要大量数据库访问才能检索.

当我有这些对象之一的新版本时,我想将其与其他对象保存,而不加载整个集合.高级常见问题解答有一些建议:

当我只想添加或删除元素时,为什么Hibernate总是初始化集合?

遗憾的是,集合API定义了方法返回值,这些值只能通过命中数据库来计算.这有三个例外:Hibernate可以添加到a <bag>,<idbag>或者<list>inverse="true"没有初始化集合的情况下声明; 返回值必须始终为true.

如果要避免额外的数据库流量(即在性能关键代码中),请重构模型以仅使用多对一关联.这几乎总是可行的.然后使用查询代替集合访问.

我是所有这一切的新手,并不是100%肯定如何重构你的模型只使用多对一的关联.任何人都可以给我一个例子,指出我的教程,以便我可以了解这将如何解决我的问题?

Art*_*ald 11

如果你有一个List或基于Set的集合,并且在你的集合中添加了一个新对象,Hibernate将始终访问数据库,因为它在保存或更新之前使用equals实现比较逐个对象 - 使用Set时 - 或通过比较使用List时的索引列.由于Set和List语义,因此需要此行为.因此,无论您拥有大量记录,应用程序的性能都会显着降低.

解决此问题的一些解决方法

转换模式使用封装的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)

使用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)

缓存 - 应用时,根据您的要求,您的配置可能会增加或降低应用程序的性能.看到这里

SQL约束 - 如果希望集合的行为类似于Set,则可以使用SQL约束,该约束可应用于列或列.看到这里

  • 我认为它确实读取了当前的集合以进行添加.这是因为它需要检查`Set`约束.即它需要查看您正在添加的实体是否已经在集合中,因为如果它已经存在则必须返回false. (4认同)

And*_*son 9

我通常这样做的方法是将集合定义为"反向".

这大致意味着: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进行查询以及迭代和显示它可能非常实用.