вчера я работал над подобной проблемой. Мне нужно было выбрать/загрузить все родительские объекты с точно заданным списком дочерних объектов. Я мог бы решить это с помощью Criteria-API, имея только один недостаток (см. * 1 ниже).
public class Project
{
public virtual int ProjectId{get;set;}
public virtual IList<Part> Parts{get;set;}
...
}
public class Part
{
public virtual int PartId{get;set;}
public virtual Project Project{get;set;} // *1 this is the drawback: I need a public property for the ForegienKey from the child to the parent
...
}
Здесь приходит Критерии:
DetachedCriteria top = DetachedCriteria.For<Project>();
foreach(Part part in searchedParts)
{
DetachedCriteria sub = DetachedCriteria.For<Part>();
sub.Add(Expresion.Eq("PartId",part.PartId));
sub.SetProjection("Project");
top.Add(Subqueries.PropertyIn("ProjectId",sub));
}
Назад к вашему примеру: SQL, будет выглядеть следующим образом.
SELECT * FROM project
WHERE
projectid IN (SELECT projectid FROM part WHERE partid = 1 /* @p0 */)
AND projectid IN (SELECT projectid FROM part WHERE partid = 2 /* @p1 */)
Basicaly добавить для каждого ребенка подзапрос, который проверяет его в Существование проекта и объединить их с и, таким образом только проект со всем, что будут отобраны дети.
Приветствия
Juy JuKa
Дополнительное использование
Я не закончил с моим кодом после этого и, если необходимо Сомон, что я должен был узнать, и я добавлю его здесь. Я надеюсь, что дополнительная информация принадлежит здесь, но я не уверен, потому что это мой первый пост на stackoverflow.com
В следующих примерах мы должны более сложную часть класса:
public class Part
{
public virtual int PartId{get;set;}
public virtual Project Project{get;set;}
public virtual PartType PartType{get;set;}
...
}
public class PartType
{
public virtual int PartTypeId{get;set;}
public virtual string Name{get;set;}
...
}
другой критерий на детские объекты
Возможно использование того же кода, если у вас нет основной (ей) ключа (ов) искомых деталей, но хотелось бы найти детали с другими свойствами.
// I am asuming building-projects with houses, gardens, garages, driveways, etc.
IEnumerable<PartType> searchedTypes = new PartType[]{housePart, gardenPart};
// could be a parameter or users choise or what ever
DetachedCriteria top = DetachedCriteria.For<Project>();
foreach(PartType type in searchedTypes)
{
DetachedCriteria sub = DetachedCriteria.For<Part>();
sub.Add(Expresion.Eq("PartType",type)); // this is all that had to be changed. We could even use more complex operations with and, or, not, etc.
sub.SetProjection("Project");
top.Add(Subqueries.PropertyIn("ProjectId",sub));
}
Ожидаемые SQL
SELECT * FROM project
WHERE
projectid IN (SELECT projectid FROM part WHERE parttype = 1 /* @p0 // aka. housePart */)
AND projectid IN (SELECT projectid FROM part WHERE parttype = 2 /* @p1 // aka. gardenPart */)
За исключением детей
Отрицать это и поиск partens, которые делают не есть искомая дети легко сделать с помощью Subqueries.PropertyNotIn вместо подзапросов .PropertyIn.
/только искавшие детей
Ровно Это была сложная часть я должен был работать на долгое время. Я хотел, чтобы родители с точно указанным списком частей. Чтобы остаться на примере строительно-проекта: Я ищу проекты домового части и guarden-части, но никаких других частей
IEnumerable<PartType> searchedTypes = new PartType[]{housePart, gardenPart};
DetachedCriteria top = DetachedCriteria.For<Project>();
ICriterion notCriterion = null;
foreach(PartType type in searchedTypes)
{
ICriterion subCriterion = Expresion.Eq("PartType",type);
DetachedCriteria sub = DetachedCriteria.For<Part>();
sub.Add(subCriterion);
sub.SetProjection("Project");
top.Add(Subqueries.PropertyIn("ProjectId",sub));
// I am collecting all valid criterions for child-objects and negate them
subCriterion = Expresion.Not(subCriterion);
notCriterion = notCriterion == null ? subCriterion:Expresion.And(notCriterion,subCriterion);
}
// with the negated criterions I exclude all parent-objects with an invalid child-object
DetachedCriteria not = DetachedCriteria.For<Part>();
not.Add(notCriterion);
sub.SetProjection("Project");
top.Add(Subqueries.PropertyNotIn("ProjectId",not));
Ожидаемые SQL
SELECT * FROM project
WHERE
projectid IN (SELECT projectid FROM part WHERE parttype = 1 /* @p0 // aka. housePart */)
AND projectid IN (SELECT projectid FROM part WHERE parttype = 2 /* @p1 // aka. gardenPart */)
AND projectid NOT IN (SELECT projectid FROM part
WHERE
NOT (parttype = 1 /* @p2 // aka. housePart */)
AND NOT (parttype = 2 /* @p3 // aka. gardenPart */)
)
(Более один дом и/или один стражник возможен, так как не выполняется никаких «дублированных» записей)
Быстрые методы <>() и .Where() из LINQ? от NHibernate? Я пытаюсь интегрировать ваш ответ в свое решение, но я не нахожу эти методы. – jsmorris
ICriteria.List() - метод NH, а IEnumerable.Where() - метод LINQ. –