Вот мое предложение:
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>();
Идея заключается в следующем: найти всех детей, у которых Name
похож на одну из names
записей.Сгруппируйте этих детей по их Parent
.Для этого Child
понадобится свойство Parent
, сопоставленное с соответствующим родителем, но в любом случае это хорошая идея.Для всех групп с размером, равным (или большим, чем, но это не должно происходить, поэтому вы можете заменить Ge
на Eq
) names.Length
, вернуть их родителя;потому что, если размер группы равен names.Length
, все имена были найдены , если предположить, что ни у одного из двух детей родителя нет одинакового имени .
Сгенерированный запрос:
SELECT
this_.Parent as y0_
FROM
Child this_
WHERE
this_.Name in (
/* */
)
GROUP BY
this_.Parent
HAVING
count(this_.Parent) >= /* names.Length */;
Я создал тестовое приложение, которое возвращало многообещающие результаты.
Если вам нужно больше работать с родителями, например, разбивать страницы на страницы или извлекать детей, вы можете разделить эту проблему на подзапрос.(обратите внимание, что строка .Fetch(x=>x.Children).Eager
не обязательна, это всего лишь пример того, что вы можете дополнительно сделать с запросом):
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, just an example
.WithSubquery.WhereProperty(x => x.Id).In(parentSubQuery )
.List();
SQL (без Fetch
):
SELECT
this_.Id as Id1_0_
FROM
Parent this_
WHERE
this_.Id in (
SELECT
this_0_.Parent as y0_
FROM
Child this_0_
WHERE
this_0_.Name in (
/* names */
)
GROUP BY
this_0_.Parent
HAVING
count(this_0_.Parent) >= /* names.length */
);
Обновление:
Если Parent <-> Child много-много, то все становится немного сложнее:
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();
Основное отличие состоит в том, что вместо группировки попрямое Parent
свойство Child
Сначала мне нужно было присоединиться к коллекции родителей.Для ссылки на каждого родителя я ввожу псевдоним parent
.
Сгенерированный SQL очень близок к исходному подходу:
SELECT
this_.Id as Id2_0_
FROM
Parent this_
WHERE
this_.Id in (
SELECT
parent1_.Id as y0_
FROM
Child this_0_
inner join
ChildToParent parents3_
on this_0_.Id=parents3_.ChildId
inner join
Parent parent1_
on parents3_.ParentId=parent1_.Id
WHERE
this_0_.Name in (
/* names */
)
GROUP BY
parent1_.Id
HAVING
count(parent1_.Id) >= /* names.Length */
);
Для моего тестового сценария это работает, так что, надеюсь, это будет и для вас.