简体   繁体   English

标准休眠加入

[英]Criteria hibernate join

I need to do a criteria that return a list of "b" object. 我需要执行一个返回“ b”对象列表的条件。 I have the following classes: 我有以下课程:

---
A
---
private BigDecimal id;
private String name;
private B b;

---
B
---
private BigDecimal id;
private String name;

I doing this: 我这样做:

Criteria criteria = getSession().createCriteria(A.class,"a").createCriteria("b");
return criteria.list();

I always get a List< A >, and i don't know how would be to get List< B >. 我总是得到一个List <A>,我不知道如何得到List <B>。 Is it that possible? 有可能吗

Edit: Using Java SE 1.7 编辑:使用Java SE 1.7

If you don't want a bidirectional relation between A and B, use an alias and then collect just b properties. 如果您不希望A和B之间存在双向关系,请使用别名,然后仅收集b属性。

List<A> aList = getSession().createCriteria(A.class, "a")
        .createAlias("a.b", "b")
        .add(Restrictions.eq("a.name", "A name")
        .add(Restrictions.eq("b.name", "B name")
        .list();
List<B> bList = new ArrayList<>(aList.size());
for (A a : aList) {
    bList.add(a.getB());
}

You can navigate to associations using a nested Criteria like this: 您可以使用嵌套的条件导航到关联,如下所示:

List<B> result = session.createCriteria( A.class )
     .add( Restrictions.like("name","he%") )
     .createCriteria( "b" )
         .add( Restrictions.like("name", "he%") )
     .list();

My "second" answer is not for Criteria but rather the CriteriaBuilder which I wouldn't recommend for small use cases but for use cases where a query needs to be created dynamically with changing conditions coming from users or other applications. 我的“第二个”答案不是针对Criteria,而是针对CriteriaBuilder ,对于小用例,我不建议使用它,而是针对需要动态创建查询,且用户或其他应用程序的条件不断变化的用例。

final CriteriaBuilder queryBuilder = getCriteriaBuilder(); // Retrieve your CriteriaBuilder here. I inject mine over CDI for example...
final CriteriaQuery<B> query = queryBuilder.createQuery( B.class ); // Type the query to it's expected end result type.

final Root<A> queryRoot = query.from( A.class ); // Select the root of the query
final Join<Object, Object> BJoin= queryRoot.join("b", JoinType.LEFT ); // "b" is the field name to use for the mapping between the root table to the joined table. In this case a.b
// The above equals "left join b on b.id = a.b.id "

// Perform a select with the Class resulting from the select and what wants to be selected. 
// It is also possible to select only a field of a table but in our case we want the whole table of B to be selected.
final Selection<B> select = queryBuilder.construct( B.class, BJoin ); 
query.select(select); // add the select to the query

// We need to remember the ParameterExpression in order to fill the where condition.
// This acts as a typed(!) blank to later fill with the condition we want to match
final ParameterExpression<String> bName = queryBuilder.parameter(String.class);

// Define the where condition using the Path<T> you retrieve from Root or Join objects.
// This will make hibernate build the condition for the correct table like b.name
final Predicate bPredicate = queryBuilder.equal( bJoin.get("name"),bName );

query.where(bPredicate); // add the where expression to the query.
// The above equals something like "where b.name = ?"

// Compile the built query to a TypedQuery
// The EntitiyManager is also injected over CDI in my usual case.
final TypedQuery<B> builtQuery = javax.persistence.EntityManager.createQuery(query);
builtQuery.setParameter(bName,"test"); // Fill in the ? of the where condition.

final List<B> resultList = builtQuery.getResultList();

This seems very heavy and complex in the beginning but it is possible to use this very dynamically, since you can just extract multiple methods out of the snippet and enable adding multiple where conditions, order by, group by etc. 一开始这似乎很繁琐,但可以非常动态地使用它,因为您可以从代码段中提取多种方法,并允许添加多个where条件,order by,group by等。

Finally I did this: 最后,我做到了:

public List<B> findXXXX(A a) {

    // A
    DetachedCriteria aCriteria = DetachedCriteria.forClass(A.class, "a");
    aCriteria.add(Restrictions.eq("a.name", "some name"));
    aCriteria.setProjection(Projections.property("a.key"));

    // B
    Criteria bcriteria = getSession().createCriteria(B.class, "b");
    bcriteria.add(Property.forName("a.key").in(aCriteria));

    return bcriteria.list();
}

A subquery because will took few records in database. 子查询,因为它将占用数据库中的很少记录。 Thanks for helping! 感谢您的帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM