Java 无需初始化的休眠计数集合大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2913160/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 14:25:53  来源:igfitidea点击:

Hibernate count collection size without initializing

javahibernatelazy-loading

提问by DD.

Is there a way I can count the size of an associated collection without initializing?

有没有一种方法可以在不初始化的情况下计算关联集合的大小?

e.g.

例如

Select count(p.children) from Parent p

(there is a good reason why I cant do this any other way as my where clause is more complicated and my from clause is a polymorphic query)

(我不能以任何其他方式执行此操作是有充分理由的,因为我的 where 子句更复杂,而我的 from 子句是多态查询)

Thanks.

谢谢。

采纳答案by Péter T?r?k

A possible solution other than queries might be mapping childrenwith lazy="extra"(in XML notation). This way, you can fetch the Parent with whatever query you need, then call parent.getChildren().size()without loading the whole collection (only a SELECT COUNTtype query is executed).

比其他的查询可能的解决方案可能是映射childrenlazy="extra"(在XML注释)。这样,您可以使用您需要的任何查询获取 Parent,然后在parent.getChildren().size()不加载整个集合的情况下调用(仅SELECT COUNT执行类型查询)。

With annotations, it would be

有了注释,这将是

@OneToMany
@org.hibernate.annotations.LazyCollection(
org.hibernate.annotations.LazyCollectionOption.EXTRA
)
private Set<Child> children = new HashSet<Child>();

Update:Quote from Java Persistence with Hibernate, ch. 13.1.3:

更新:引用自Java Persistence with Hibernate,ch。13.1.3:

A proxy is initialized if you call any method that is not the identifier getter method, a collection is initialized if you start iterating through its elements or if you call any of the collection-management operations, such as size()and contains(). Hibernate provides an additional setting that is mostly useful for large collections; they can be mapped as extra lazy. [...]

[Mapped as above,] the collection is no longer initialized if you call size(), contains(), or isEmpty()— the database is queried to retrieve the necessary information. If it's a Mapor a List, the operations containsKey()and get()also query the database directly.

如果您调用任何不是标识符 getter 方法的方法,则代理会被初始化,如果您开始遍历其元素或调用任何集合管理操作(例如size()和 ),则会初始化集合contains()。Hibernate 提供了一个额外的设置,对于大型集合最有用;它们可以被映射为extra lazy。[...]

[映射为以上,所述收集不再初始化,如果你打电话size()contains()或者isEmpty()-查询数据库来获取必要的信息。如果它是一个Map或一List,操作containsKey()get()也直接查询数据库。

So with an entity mapped as above, you can then do

因此,使用如上映射的实体,您可以执行以下操作

Parent p = // execute query to load desired parent
// due to lazy loading, at this point p.children is a proxy object
int count = p.getChildren().size(); // the collection is not loaded, only its size

回答by Steve Ebersole

You can use Session#createFilter which is a form of HQL which explicitly operates on collections. For example, you mention Parent and Children so if you have a Person p the most basic form would be:

您可以使用 Session#createFilter ,它是一种显式操作集合的 HQL 形式。例如,你提到了 Parent 和 Children,所以如果你有一个 Person p,最基本的形式是:

session.createFilter( p.getChildren(), "" ).list()

This simply returns you a list of the children. It is important to note that the returned collection is not "live", it is not in any way associated with p.

这只是返回一个孩子的列表。需要注意的是,返回的集合不是“实时”的,它与 p 没有任何关联。

The interesting part comes from the second argument. This is an HQL fragment. Here for example, you might want:

有趣的部分来自第二个论点。这是一个 HQL 片段。例如,您可能需要:

session.createFilter( p.getChildren(), "select count(*)" ).uniqueResult();

You mentioned you have a where clause, so you also might want:

你提到你有一个 where 子句,所以你可能还想要:

session.createFilter( p.getChildren(), "select count(*) where this.age > 18" ).uniqueResult();

Notice there is no from clause. That is to say that the from clause is implied from the association. The elements of the collection are given the alias 'this' so you can refer to it from other parts of the HQL fragment.

注意没有 from 子句。也就是说,from 子句是从关联中隐含的。集合的元素被赋予别名“this”,因此您可以从 HQL 片段的其他部分引用它。

回答by neel4soft

You can do the same like this:

你可以这样做:

@Override
public FaqQuestions getFaqQuestionById(Long questionId) {
    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    FaqQuestions faqQuestions = null;
    try {
        faqQuestions = (FaqQuestions) session.get(FaqQuestions.class,
                questionId);
        Hibernate.initialize(faqQuestions.getFaqAnswers());

        tx.commit();
        faqQuestions.getFaqAnswers().size();
    } finally {
        session.close();
    }
    return faqQuestions;
}

Just use faqQuestions.getFaqAnswers().size()nin your controller and you will get the size if lazily intialised list, without fetching the list itself.

只需在控制器中使用 faqQuestions.getFaqAnswers().size() ,如果延迟初始化列表,您将获得大小,而无需获取列表本身。