Hibernate - 如何在Collection中保存一个新项目而不加载整个Collection [英] Hibernate - How to persist a new item in a Collection without loading the entire Collection

查看:127
本文介绍了Hibernate - 如何在Collection中保存一个新项目而不加载整个Collection的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



当我有一个这样的对象的新版本时,我想保存它其他人没有加载整个集合。高级FAQ对此有一些建议:


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



不幸的是,collections API定义了只能通过点击数据库来计算的方法返回值。有三个例外:Hibernate可以添加到< bag> < idbag> < list> ,不需要初始化集合;返回值必须始终为真。



如果您想要避免额外的数据库流量(即在性能严重的代码中),请重构您的模型以仅使用多对多一个协会。这几乎总是可能的。然后使用查询代替收藏访问。


我对这一切都很陌生,并不是100%确定如何重构您的模型只使用多对一的关联。任何人都可以请给我一个例子,指向我的教程,以便我可以学习如何解决我的问题?

当你有一个基于列表或集合的集合,并向集合中添加一个新对象时,Hibernate将始终命中数据库,因为它在保存或更新之前使用equals实现比较逐一对象 - 使用集合时 - 或者通过比较使用List时的索引列。由于设置和列表语义,此行为是必需的。因此,应用程序的性能会显着降低,无论您是否拥有一堆记录。



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

使用包装袋集合加上您希望的设置或列表作为属性公开的转换模式

  @实体
公开课一个{

私人收藏<许多> manyCollection = new ArrayList< Many>();

@Transient
public Set< Many> getManyCollectionAsSet(){返回新的HashSet< Many>(manyCollection); }
public void setManyCollectionAsSet(Set< Many> manySet){manyCollection = new ArrayList< Many>(manySet); }请注意,与Hibernate不同的是,JPA规范不允许私人可见性。您应该使用public或protected来代替
* /
@OneToMany(cascade = ALL)
private Collection< Many> getManyCollection(){return manyCollection; }
private void setManyCollection(Collection< Many> manyCollection){this.manyCollection = manyCollection; }


改用ManyToOne OneToMany

  @Entity 
公开课一个{

/ **
*无论是级联还是参考
* /

}

@实体
公共类许多{b
$ b私人一个;

@ManyToOne(cascade = ALL)
public一个getOne(){return one; }
public void setOne(One one){this.one = one}

}

缓存 - 根据您的要求应用时,配置可能会增加或减少应用程序的性能。请参阅此处



SQL约束 - 如果您希望集合的行为类似于集合,您可以使用SQL约束,该约束可应用于列或组的列。请参阅此处


I have a collection in my model that contains a set of 'previous versions' of my root domain object. The previous versions are therefore 'immutable' and we will never want to update them, and only want to add past versions as they arise. Also the 'versioned' domain object is fairly complex and causes heavy database access to retrieve.

When I have a new version of one of these objects I want to save it with the others without loading the entire set. The Advanced FAQ has some advice on this:

Why does Hibernate always initialize a collection when I only want to add or remove an element?

Unfortunately the collections API defines method return values that may only be computed by hitting the database. There are three exceptions to this: Hibernate can add to a <bag>, <idbag> or <list> declared with inverse="true" without initializing the collection; the return value must always be true.

If you want to avoid extra database traffic (ie. in performance critical code), refactor your model to use only many-to-one associations. This is almost always possible. Then use queries in place of collection access.

I am new to all of this and am not 100% sure on how to refactor your model to use only many-to-one associations. Can anyone please give me an example of point me to a tutorial so that I can learn how this will resolves my issue?

解决方案

When you have a List or Set-based collection and you add a new object into your collection, Hibernate will always hit the database because it compare one by one object by using equals implementation before saving or updating - when using a Set - or by comparing a index column when using a List. This behavior is needed because of the Set and List semantic. Because of that, the performance of your application can decrease significantly whether you have a bunch of records.

Some workaround to overcome this issue

Conversion pattern by using a encapsuled Bag collection plus your desired Set or List exposed as a property

@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; }

}

Use ManyToOne instead of 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 }

}

Caching - when applied because of, depending on your requirements, your configuration can increase or decrease the performance of your application. See here

SQL constraint - If you want a collection that behaves like a Set, you can use a SQL constraint, which can be applied to a column or set of columns. See here

这篇关于Hibernate - 如何在Collection中保存一个新项目而不加载整个Collection的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆