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