Вернуть класс из вложенной коллекции, используя NHibernate - PullRequest
3 голосов
/ 16 июня 2009

Доман:

class Action
    Products: IList of class ActionProducts: 
          Category: class Category
                Products: IList of class Product

Теперь я хочу это:

 var products = from a in Session.Linq<Action>()
                from ap in a.Products
                from p in ap.Category.Products
                where a.Name == name
                select p;

И этот Linq на самом деле работает, но: 1. производит выбор для всех таблиц, а не только для продуктов 2. создает левые внешние объединения, а не внутренние 3. Distinct () в запросе не работает (хотя ToList (). Distinct ( ) работает).

Также может быть сделано с помощью SelectMany (a => a.Products) .SelectMany (ap => ap.Category.Products), но это не работает вообще с текущим NHibernate.Linq.

Итак, я хочу использовать ICriteria. Но я не вижу, как вернуть товар, а не действие?

 ICriteria criteria = Session.CreateCriteria(typeof(Action))
    .Add(Expression.Eq("Name", name))
    .CreateAlias("Products", "ap")
    .CreateAlias("ap.Category.Products", "p")
    .SomehowReturnMeOnly("p");

Так как мне SomehowReturnMeOnly ("p")? Так что я могу сделать

return criteria.List<Product>();

что не получится, потому что ICriteria выбирает Действия, а не Продукты?

Я могу рассмотреть HQL, но на самом деле мне не нравятся строковые запросы ... Например, вот HQL, который работает и выдает именно тот SQL, который мне нужен:

 IQuery query = Session.CreateQuery("select distinct p from Action a inner join a.Products as ap inner join ap.Category.Products as p");
 return query.List<Product>();

Ответы [ 3 ]

2 голосов
/ 16 июня 2009

Теперь нечто подобное можно сделать (имея в виду, что CreateAlias ​​может выполнять только 1 уровень), используя

 DetachedCriteria dq = DetachedCriteria.For<Action>()
     .Add(Expression.Eq("Name", name))
     .CreateAlias("Products", "ap")
     .CreateAlias("ap.Category", "c")
     .CreateAlias("c.Products", "p")
     .SetProjection(Projections.Property("p.Id"));
  ICriteria criteria = Session.CreateCriteria(typeof(Product))
     .Add(Subqueries.PropertyIn("Id", dq));
  return criteria.List<Product>();

Это работает и проходит тестирование, но выдает «SELECT FROM products WHERE id in (subquery)», что может быть даже лучше (не требуется DISTINCT), но это не то, чего я хотел достичь. Похоже, Criteria API очень, очень ограничительный. Итак имеем:

  1. HQL с недостатками строкового запроса
  2. Criteria API с множеством ограничений и иногда ужасным кодом для достижения простых результатов
  3. NH-Linq, который выглядит очень многообещающе, но сейчас не завершен.

Так что, думаю, я буду придерживаться HQL, пока Linq не будет готов.

1 голос
/ 16 июня 2009

Вам нужно использовать проекции, что-то вроде этого:

ICriteria criteria = Session.CreateCriteria(typeof(Action))
    .Add(Expression.Eq("Name", name))
    .CreateAlias("Products", "ap")
    .CreateAlias("ap.Category.Products", "p")
    .SetProjection(Projections.Property("ap.Category.Products"))
    .List<Product>();

Посмотрите документы nhibernate здесь для некоторых примеров.

0 голосов
/ 16 июня 2009

Ну, подумав об ответе Криса ... Я попробовал это, и это сработало:

 ICriteria criteria = Session.CreateCriteria(typeof(Action))
    .Add(Expression.Eq("Name", name))
    .CreateAlias("Products", "ap")
    .CreateAlias("ap.Category", "c")
    .SetProjection(Projections.Distinct(Projections.Property("c.Products")));

Похоже, NHibernate не допускает глубокого вложения свойств проекции, что странно. И это тоже не работает, глядя на сгенерированный SQL, я вижу, что он выбирает только

SELECT distinct c2_.Id as y0_ FROM ... Categories c2_ ...

т.е. он на самом деле не выбирает продукты, что приводит к сбою моего модульного теста, поскольку возвращаемый список содержит только нули вместо экземпляров Product.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...