Hibernate query - select one Object which have only one Set element which meets criteria -


i have 3 classes:

public class a{   private string name; }  public class b{   private aobj; }  public class c{   private set<b> bobj; } 

and following criteria:

session session = opensession(); criteria c1 = session.createcriteria(c.class); criteria c2 = c1.createcriteria("bobj"); criteria c3 = c2.createcriteria("aobj"); c2.add(restrictions.eq("name",name)); 

which work , c1.uniqueresult() expected 1 (name unique)

and question: way c object 1 element in set contain bobj meets criteria c2? (supposing set bobj have more 1 element)

update 1: actual result (c.class json)

{ bobj : [     1: { aobj :       { name : name1}},    2: { aobj :       { name : name2}},    3: { aobj :       { name : name3}}  ]}  

expected result name = name1 :

{ bobj : [     1: { aobj :       { name : name1}}    ] } 

so after query bobj have 1 element in list meets criteria name = name1

there many ways that, maybe can use 1 of following fits needs best.

e.g. if have example instance of b handy, use criteriabuilder. pass example object (bobj) expect member of association , specify associations size:

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

if criteria more, define (implicit) join behavior selection , add restrictions:

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

or if jpql, use like:

final typedquery<c> query = entitymanager.createquery(                 "select c c c join c.bobj b join b.aobj c.bobj.size = 1 , a.name = :name ", c.class); query.setparameter("name", "test"); 

if need play with, here test try out. change name ("test") or uncomment second association member test restrictions:

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 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 1 result!", resultlist.size(), is(1));     }      @test     public void criteriatest() {         final 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 1 result!", resultlist.size(), is(1));      }      @test     public void jpqltest() {         final 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 c c join c.bobj b join b.aobj c.bobj.size = 1 , a.name = :name ", c.class);         query.setparameter("name", "test");         final list<c> resultlist = query.getresultlist();          assertthat("should 1 result!", resultlist.size(), is(1));     }  } 

the mapping test like:

@entity public class {      @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 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;     }  } 

i tend typesafe solution, maybe first or last one. or think using metamodel generator.

update:

after nailing down problem in comments add test make problem more clear (and keep origin answer history purposes).

accessing unfiltered association give results (either eager on query time or lazy on accessing it). 1 solution filter before access , convert projection or something. maybe can play around test find way that:

@test public void jpqltestwithdelayedfilterquery() {     final string filterfieldname = "name";     final string filterfieldvalue = "test";     // 1 want bs     final aobj = new a();     aobj.setname(filterfieldvalue);     entitymanager.persist(aobj);      // b should pass filter     final b bobj = new b();     bobj.setaobj(aobj);     entitymanager.persist(bobj);      // not matching filter     final aobj2 = new a();     aobj2.setname("testxxx");     entitymanager.persist(aobj2);      // don't want b here     final b bobj2 = new b();     bobj2.setaobj(aobj2);     entitymanager.persist(bobj2);      // b test first query     final b bobj3 = new b();     bobj3.setaobj(aobj2);     entitymanager.persist(bobj3);      // 1 returned first query     final c cobj = new c();     cobj.getbobj().add(bobj);     cobj.getbobj().add(bobj2);     entitymanager.persist(cobj);      // c test first query     final c cobj2 = new c();     cobj2.getbobj().add(bobj3);     entitymanager.persist(cobj2);      // let's cs need     final session session = entitymanager.unwrap(session.class);     final query cquery = session.createquery(             "select c c c inner join c.bobj b inner join b.aobj a.name = :name ");     cquery.setparameter(filterfieldname, filterfieldvalue);     final list cresults = cquery.list();     assertthat("should 1 c result!", cresults.size(), is(1));      // sadly b collection initialized fully, @ latest on accessing it, 2 bs here :/     final c cresult = (c)cresults.iterator().next();     assertthat("should 2 initialized b results here!", cresult.getbobj().size(), is(2));      // way getting our needed bs filter (imagine did not use before)     final query query = session.createfilter(cresult.getbobj(), "where this.aobj.name = :name");     query.setparameter(filterfieldname, filterfieldvalue);     final list bresult = query.list();     assertthat("should 1 filtered b result here!", bresult.size(), is(1)); } 

Comments

Popular posts from this blog

inversion of control - Autofac named registration constructor injection -

verilog - Systemverilog dynamic casting issues -

ios - Change Storyboard View using Seague -