NHibernate Как выполнить запрос к свойству IList <string>? - PullRequest
10 голосов
/ 31 июля 2009

Я пытаюсь выполнить запрос к свойству IList в одном из классов моего домена, используя NHibernate. Вот простой пример для демонстрации:

public class Demo
{
    public Demo()
    {
        this.Tags = new List<string>();
    }
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<string> Tags { get; set; }
}

Отображается так:

<class name="Demo">
<id name="Id" />
<property name="Name" />
<bag name="Tags">
  <key column="DemoId"/>
  <element column="Tag" type="String" />
</bag>

И я могу нормально сохранять и восстанавливать. Теперь для запроса экземпляров моего класса домена, где свойство Tags содержит указанное значение:

var demos = this.session.CreateCriteria<Demo>()
            .CreateAlias("Tags", "t")
            .Add(Restrictions.Eq("t", "a"))
            .List<Demo>();

Приводит к ошибке: коллекция не была ассоциацией: Demo.Tags

var demos = (from d in this.session.Linq<Demo>()
                     where d.Tags.Contains("a")
                     select d).ToList();

Приводит к ошибке: ссылка на объект не установлена ​​для экземпляра объекта.

var demos = this.session.CreateQuery("from Demo d where :t in elements(d.Tags)")
            .SetParameter("t", "a")
            .List<Demo>();

Работает нормально, но поскольку у моего реального предметного класса много свойств, и я создаю сложный динамический запрос, выполнение уродливых манипуляций со строками - не мой первый выбор. Я бы предпочел использовать ICriteria или Linq. У меня есть пользовательский интерфейс, в который можно ввести много разных критериев поиска. Код, который создает ICriteria прямо сейчас, состоит из десятков строк. Я бы очень не хотел превращать это в манипуляции со строками HQL.

Ответы [ 6 ]

4 голосов
/ 05 ноября 2014

Как указано здесь:

17.1.4.1. Псевдоним и ссылка на недвижимость

мы можем использовать:

...
A collection key             {[aliasname].key}      ORGID as {coll.key}
The id of an collection      {[aliasname].id}       EMPID as {coll.id}
The element of an collection {[aliasname].element}  XID as {coll.element}
...

есть небольшая ошибка в документе ... вместо ".element" мы должны использовать ".elements"

var demos = this.session.CreateCriteria<Demo>()
        .CreateAlias("Tags", "t")

        // instead of this
        // .Add(Restrictions.Eq("t", "a"))

        // we can use the .elements keyword
        .Add(Restrictions.Eq("t.elements", "a"))

        .List<Demo>();
4 голосов
/ 31 июля 2009

Так что из-за ограничений API Criteria я решил изогнуть свои доменные классы, чтобы они подходили.

Я создал класс сущности для тега. Я даже не мог создать его как объект стоимости. У него должен был быть свой идентификатор.

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

3 голосов
/ 31 июля 2009

HQL:

from Demo d where :val in elements(d.Tags)
3 голосов
/ 31 июля 2009

Вам нужно использовать подкритерии, а не псевдоним. Это должно работать:

var demos = this.session.CreateCriteria<Demo>()
            .CreateCriteria("Tags")
            .Add(Restrictions.Eq("Tag", "a"))
            .List<Demo>();
2 голосов
/ 27 октября 2010

Переключение на класс через строку - это один из компромиссов. Использование HQL вместо ICriteria - это другое. Однако существует третий компромисс: используйте собственный SQL. Попробуйте это.

var demos = Session.CreateCriteria<Demo>()
    .Add(Expression.Sql(
        "EXISTS (SELECT 1 FROM [Tags] custom_sql_t WHERE custom_sql_t.[DemoId] = {alias}.[Id] AND custom_sql_t.[Tag] = ?)",
        "a",
        NHibernateUtil.String))
    .List<Demo>();

Это приводит к тому, что следующий запрос SQL генерируется NHibernate 2.1.2.4000 ...

exec sp_executesql N'SELECT this_.Id as Id2_0_, this_.Version as Version2_0_, this_.Name as Name2_0_ FROM Demo this_ WHERE EXISTS (SELECT 1 FROM [Tags] custom_sql_t WHERE custom_sql_t.[DemoId] = this_.[Id] AND custom_sql_t.[Tag] = @p0)',N'@p0 nvarchar(1)',@p0=N'a'

Смотрите этот пост для другого примера ...

NHibernate - Запрос из коллекции типов значений (не для объекта) для решения Выберите N + 1

0 голосов
/ 05 декабря 2016

Это возможно путем создания отдельного критерия:

ICriteria demoCriteria = session.CreateCriteria<Demo>();
...
demoCriteria.Add(Restrictions...);
...
ICriteria tagCriteria = demoCriteria.CreateCriteria("Tags");
tagCriteria.Add(Restrictions.In("elements", new {"Tag1", "Tag2", ...}));

return demoCriteria.List<Demo>();
...