Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate查询-选择一个对象,该对象只有一个满足条件的集合元素_Hibernate_Criteria_Hibernate Criteria - Fatal编程技术网

Hibernate查询-选择一个对象,该对象只有一个满足条件的集合元素

Hibernate查询-选择一个对象,该对象只有一个满足条件的集合元素,hibernate,criteria,hibernate-criteria,Hibernate,Criteria,Hibernate Criteria,我有三门课: public class A{ private String name; } public class B{ private A aObj; } public class C{ private Set<B> bObj; } 哪个工作正常,c1.uniqueResult()是预期的(名称是唯一的) 现在的问题是: 是否有任何方法可以获得集合中只有一个元素的C对象,该元素只包含满足条件c2的bObj? (假设集合bObj有多个元素) 更新1: 实际结果是(

我有三门课:

public class A{
  private String name;
}

public class B{
  private A aObj;
}

public class C{
  private Set<B> bObj;
}
哪个工作正常,c1.uniqueResult()是预期的(名称是唯一的)

现在的问题是: 是否有任何方法可以获得集合中只有一个元素的C对象,该元素只包含满足条件c2的bObj? (假设集合bObj有多个元素)

更新1: 实际结果是(C.class作为JSON)

name=name1的预期结果为:

{ bObj : [ 
   1: { aObj : 
     { name : name1}}
   ]
}

因此,在查询之后,bObj在列表中只有一个元素符合条件name=name1

有很多方法可以做到这一点,也许您可以使用以下最适合您需要的方法之一

例如,如果手边有一个示例B实例,请使用CriteriaBuilder。只需传递您希望成为关联成员的示例对象(bObj),并指定关联大小:

final Root<C> selection = createQuery.from(C.class);
createQuery.select(selection).where(
            criteriaBuilder.isMember(bObj, selection.<Set<B>>get("bObj")),
            criteriaBuilder.equal(criteriaBuilder.size(selection.<Set<B>>get("bObj")), 1));
或者,如果您喜欢JPQL,只需使用以下内容:

final TypedQuery<C> query = entityManager.createQuery(
                "SELECT c from C c JOIN c.bObj b JOIN b.aObj a where c.bObj.size = 1 AND a.name = :name ", C.class);
query.setParameter("name", "test");
@Entity
public class A {

    @Id
    @GeneratedValue
    private long id;

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

@Entity
public class B {

    @Id
    @GeneratedValue
    private long id;

    @OneToOne
    private A aObj;

    public void setaObj(A aObj) {
        this.aObj = aObj;
    }

}

@Entity
public class C {

    @Id
    @GeneratedValue
    private long id;

    @OneToMany
    private Set<B> bObj = new HashSet<>();

    public Set<B> getbObj() {
        return bObj;
    }

    public void setbObj(Set<B> bObj) {
        this.bObj = bObj;
    }

}

感谢您花时间给出如此复杂的答案,但问题是我只想在集合bObj中找到符合条件的对象。在您的示例中,我们得到了对象C,它在bObj集合中正好有一个元素,但没有一个cObj在bObj集合中只有一个元素(正如我在问题中提到的:假设集合bObj有多个元素),我用实际结果和预期结果更新我的问题。再次谢谢你,现在我明白了。但这样做是不可能的,因为关联的加载可能稍后(延迟)完成,这取决于获取策略,而不是此查询的一部分。也许你需要像数据库游标或类似的东西,或者返回一个自定义投影。更新了我的答案:)太好了。再次感谢您的回答:)
final Criteria criteria = entityManager.unwrap(Session.class).createCriteria(C.class, "c");
criteria.createAlias("c.bObj", "b");
criteria.createAlias("b.aObj", "a");
criteria.add(Restrictions.sizeEq("c.bObj", 1));
criteria.add(Restrictions.eq("a.name", "test"));
final TypedQuery<C> query = entityManager.createQuery(
                "SELECT c from C c JOIN c.bObj b JOIN b.aObj a where c.bObj.size = 1 AND a.name = :name ", C.class);
query.setParameter("name", "test");
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class ListTests {

    @PersistenceContext
    private EntityManager entityManager;

    @Test
    public void criteriaBuilderTest() {
        final A aObj = new A();
        aObj.setName("test");
        entityManager.persist(aObj);

        final B bObj = new B();
        bObj.setaObj(aObj);
        entityManager.persist(bObj);

        final B bObj2 = new B();
        bObj2.setaObj(aObj);
        entityManager.persist(bObj2);

        final C cObj = new C();
        cObj.getbObj().add(bObj);
        // cObj.getbObj().add(bObj2);
        entityManager.persist(cObj);

        final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        final CriteriaQuery<C> createQuery = criteriaBuilder.createQuery(C.class);
        final Root<C> selection = createQuery.from(C.class);
        createQuery.select(selection).where(criteriaBuilder.isMember(bObj, selection.<Set<B>>get("bObj")),
                criteriaBuilder.equal(criteriaBuilder.size(selection.<Set<B>>get("bObj")), 1));
        final List<C> resultList = entityManager.createQuery(createQuery).getResultList();
        assertThat("Should get exactly one result!", resultList.size(), is(1));
    }

    @Test
    public void criteriaTest() {
        final A aObj = new A();
        aObj.setName("test");
        entityManager.persist(aObj);

        final B bObj = new B();
        bObj.setaObj(aObj);
        entityManager.persist(bObj);

        final B bObj2 = new B();
        bObj2.setaObj(aObj);
        entityManager.persist(bObj2);

        final C cObj = new C();
        cObj.getbObj().add(bObj);
        // cObj.getbObj().add(bObj2);
        entityManager.persist(cObj);

        final Criteria criteria = entityManager.unwrap(Session.class).createCriteria(C.class, "c");
        criteria.createAlias("c.bObj", "b");
        criteria.createAlias("b.aObj", "a");
        criteria.add(Restrictions.sizeEq("c.bObj", 1));
        criteria.add(Restrictions.eq("a.name", "test"));
        final List<C> resultList = criteria.list();

        assertThat("Should get exactly one result!", resultList.size(), is(1));

    }

    @Test
    public void jpqlTest() {
        final A aObj = new A();
        aObj.setName("test");
        entityManager.persist(aObj);

        final B bObj = new B();
        bObj.setaObj(aObj);
        entityManager.persist(bObj);

        final B bObj2 = new B();
        bObj2.setaObj(aObj);
        entityManager.persist(bObj2);

        final C cObj = new C();
        cObj.getbObj().add(bObj);
        // cObj.getbObj().add(bObj2);
        entityManager.persist(cObj);

        final TypedQuery<C> query = entityManager.createQuery(
                "SELECT c from C c JOIN c.bObj b JOIN b.aObj a where c.bObj.size = 1 AND a.name = :name ", C.class);
        query.setParameter("name", "test");
        final List<C> resultList = query.getResultList();

        assertThat("Should get exactly one result!", resultList.size(), is(1));
    }

}
@Entity
public class A {

    @Id
    @GeneratedValue
    private long id;

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

@Entity
public class B {

    @Id
    @GeneratedValue
    private long id;

    @OneToOne
    private A aObj;

    public void setaObj(A aObj) {
        this.aObj = aObj;
    }

}

@Entity
public class C {

    @Id
    @GeneratedValue
    private long id;

    @OneToMany
    private Set<B> bObj = new HashSet<>();

    public Set<B> getbObj() {
        return bObj;
    }

    public void setbObj(Set<B> bObj) {
        this.bObj = bObj;
    }

}
@Test
public void jpqlTestWithDelayedFilterQuery() {
    final String filterFieldName = "name";
    final String filterFieldValue = "test";
    // this is the one we want to get the Bs for
    final A aObj = new A();
    aObj.setName(filterFieldValue);
    entityManager.persist(aObj);

    // this is the B which should be pass the filter
    final B bObj = new B();
    bObj.setaObj(aObj);
    entityManager.persist(bObj);

    // A not matching the filter
    final A aObj2 = new A();
    aObj2.setName("testXXX");
    entityManager.persist(aObj2);

    // we don't want to get that B here
    final B bObj2 = new B();
    bObj2.setaObj(aObj2);
    entityManager.persist(bObj2);

    // only another B to test the first query
    final B bObj3 = new B();
    bObj3.setaObj(aObj2);
    entityManager.persist(bObj3);

    // this is the one returned by first query
    final C cObj = new C();
    cObj.getbObj().add(bObj);
    cObj.getbObj().add(bObj2);
    entityManager.persist(cObj);

    // only another C to test the first query
    final C cObj2 = new C();
    cObj2.getbObj().add(bObj3);
    entityManager.persist(cObj2);

    // let's get only the Cs we need
    final Session session = entityManager.unwrap(Session.class);
    final Query cQuery = session.createQuery(
            "SELECT c from C c INNER JOIN c.bObj b INNER JOIN b.aObj a where a.name = :name ");
    cQuery.setParameter(filterFieldName, filterFieldValue);
    final List cResults = cQuery.list();
    assertThat("Should get exactly one C result!", cResults.size(), is(1));

    // sadly the B collection is initialized fully, at latest on accessing it, so two Bs here :/
    final C cResult = (C)cResults.iterator().next();
    assertThat("Should get two already initialized B results here!", cResult.getbObj().size(), is(2));

    // the only way is getting our needed Bs with a filter (imagine you did not use it before)
    final Query query = session.createFilter(cResult.getbObj(), "where this.aObj.name = :name");
    query.setParameter(filterFieldName, filterFieldValue);
    final List bResult = query.list();
    assertThat("Should get exactly one filtered B result here!", bResult.size(), is(1));
}