Я достаточно новичок в nHibernate и пытался написать запрос. Кажется, я не могу понять это правильно. В моей модели есть «Продукт», который содержит коллекцию «Компонент». Мне нужно найти все продукты, содержащие какие-либо компоненты, в которых ссылка на компонент начинается с буквы «G». Я пробовал это:

var matching = session.QueryOver<Product>()
   .JoinQueryOver<Component>(p => p.Components)
   .Where(c => c.ComponentReference.StartsWith("G")).List();

Однако я получаю сообщение об ошибке компиляции: «Delegate System.Func >> не принимает 1 параметр.

В JoinQueryOver есть перегрузка, где я могу передать выражение >>

Поэтому я бы подумал, что мой запрос будет работать, поскольку ICollection реализует IEnumerable.

Я пробовал различные другие способы использования .Cast и JoinAlias, но они кажутся излишне сложными.

Может ли кто-нибудь указать, в чем я ошибаюсь?

Заранее спасибо

1
user3161050 8 Фев 2014 в 20:38

1 ответ

Лучший ответ

В этом случае я бы посоветовал использовать подзапрос. Это могло выглядеть так

Product product = null;
Component component = null;

// the subselect, returning the Product.ID
// only if the Component.ComponentReference is like G%
var subQuery = QueryOver.Of<Component>(() => component)
    .WhereRestrictionOn(() => component.ComponentReference)
        .IsLike("G", MatchMode.Start)
    .Select(c => c.Product.ID);

// the root Product
var query = session.QueryOver<Product>(() => product)
    .WithSubquery
    .WhereProperty(() => product.ID) 
    .In(subQuery);

// and finally the list
var list = query
    .List<Product>();

Результирующий SQL будет таким:

SELECT product
FROM product
WHERE productId IN (SELECT ProductId FROM Component WHERE ComponenentReferece LIKE 'G%')

А зачем использовать подзапрос вместо JOIN? потому что объединение в этом случае приведет к картезианскому произведению. Набор возвращенных продуктов будет умножен на все компоненты, начиная с G%.

Подзапрос приведет к чистому плоскому набору продуктов, поэтому мы можем правильно использовать разбиение на страницы по нему (.Take() .Skip())

0
marc_s 18 Сен 2017 в 23:42
Спасибо за вашу помощь. Я заставил его работать, используя мою идею, но ваша помощь заставила меня понять 2 ошибки. var match = session.QueryOver () .JoinQueryOver (p => p.Components) .Where (c => c.ComponentCode.IsLike ("G", MatchMode.Start)). List (); возвратное соответствие; мои ошибки: 1) использовал неправильный класс! (Лицо ладони) ProductComponent, а не компонент. В продукте есть ICollection компонентов продукта, а не компонентов 2) IsLike, а не StartsWith. Прочитав ваш ответ, я понял, что, поскольку компонент не имеет свойства продукта, я явно использовал неправильный класс! БЛАГОДАРНОСТЬ :-)
 – 
user3161050
8 Фев 2014 в 21:23
Я знал, что ты можешь делать это по-своему;) Просто нужны были подсказки. Не сдавайся. NHibernate - отличный инструмент. Пожалуйста, уделите немного времени и внимательно прочтите эту главу: nhforge.org/doc/ nh / en / index.html # queryqueryover, это очень поможет ...
 – 
Radim Köhler
8 Фев 2014 в 22:13