c# - Restrict QueryOver by child collection using nHibernate -
i trying parent entity entities in child collection in list.
for example:
public class parent { public virtual int id {get;set;} public virtual list<child> children {get;set;} } public class child { public virtual int id {get;set;} public virtual string name {get;set;} } i've tried various combinations of joins , restrictions can't seem hit spot.
so please suggestions.
current example below:
public ilist<lead> getallavailable(string[] names) { var result = session.createcriteria<parent>() .createcriteria("children") .add(expression.in("name", names)).list<parent>(); return result; } edit:
this sql equivilent:
select * dbo.parent join ( select p.id dbo.parent p join dbo.parenttochildren on p.id = dbo.parentstochildren.parent_id join dbo.child on dbo.parenttochildren.child_id = dbo.child.id name in ( 'foo', 'bar' ) group p.id having count(1) > 1 ) foo on dbo.parent.id = foo.id
here's suggestion:
var parents = session.queryover<child>() .whererestrictionon(x => x.name).isin(names) .select(projections.group<child>(x => x.parent)) .where(restrictions.ge(projections.count<child>(x => x.parent), names.length)) .list<parent>(); the idea follows: find children have name 1 of names entries. group children parent. child need parent property mapped respective parent this, that's idea anyway. groups size equal (or greater than, shouldn't happen, replace ge eq) names.length, return parent; because if size of group equal names.length, names have been found assuming no 2 children of parent have same name.
the generated query:
select this_.parent y0_ child this_ this_.name in ( /* */ ) group this_.parent having count(this_.parent) >= /* names.length */; i've created test app returned promising results.
if need more parents, paging or fetching children, split problem sub query (note .fetch(x=>x.children).eager line not required, it's example can further query):
var parentsubquery = queryover.of<child>() .whererestrictionon(x => x.name).isin(names) .select(projections.group<child>(x => x.parent)) .where(restrictions.ge(projections.count<child>(x => x.parent), names.length)); var parents = session.queryover<parent>() .fetch(x=>x.children).eager // not necessary, example .withsubquery.whereproperty(x => x.id).in(parentsubquery ) .list(); sql (without fetch):
select this_.id id1_0_ parent this_ this_.id in ( select this_0_.parent y0_ child this_0_ this_0_.name in ( /* names */ ) group this_0_.parent having count(this_0_.parent) >= /* names.length */ ); update:
if parent<->child many-to-many, things little bit trickier:
parent parent = null; var parentsubquery = queryover.of<child>() .whererestrictionon(x => x.name).isin(names) .joinqueryover(x => x.parents, () => parent) .where(restrictions.ge(projections.count(() => parent.id), names.length)) .select(projections.group(() => parent.id)); var parents = session.queryover<parent>() .withsubquery.whereproperty(x => x.id).in(parentsubquery) .list(); the main difference instead of grouping direct parent property of child first needed join parents collection. reference each parent there introduce alias parent.
the generated sql pretty close original approach:
select this_.id id2_0_ parent this_ this_.id in ( select parent1_.id y0_ child this_0_ inner join childtoparent parents3_ on this_0_.id=parents3_.childid inner join parent parent1_ on parents3_.parentid=parent1_.id this_0_.name in ( /* names */ ) group parent1_.id having count(parent1_.id) >= /* names.length */ ); for test scenario works, you, too.
Comments
Post a Comment