Фильтрация QueryOver для коллекции строк: NullReferenceException

У меня есть предметы. Каждый элемент принадлежит группе. И каждый элемент имеет (возможно, пустой) список тегов (строк), полезных для ускорения текстового поиска. Поиск должен найти элементы, соответствующие их описанию, описанию группы, к которой они принадлежат, или одному или нескольким тегам (все в условиях ИЛИ).

Я пытаюсь выбрать элементы по ключу поиска через следующий QueryOver.

Item i = null;
ItemGroup g = null;
String tag = null;

session
    .QueryOver<Item>(() => i)
    .JoinAlias(x => x.Group, () => g, JoinType.InnerJoin)
    .JoinAlias(x => x.Tags, () => tag, JoinType.LeftOuterJoin) //left outher join because it is possible for an item to have no tags at all.
    .Where(
        new Disjunction()
            .Add(Restrictions.On(() => p.Description).IsInsensitiveLike(searchKey, MatchMode.Anywhere))
            .Add(Restrictions.On(() => g.Description).IsInsensitiveLike(searchKey, MatchMode.Start))
            .Add(Restrictions.On(() => tag).IsInsensitiveLike(searchKey, MatchMode.Start)) //this condition throws an exception
    )
    .Take(maxResults)
    .Future();

Класс элемента отображается следующим образом:

<class name="Item" table="Items">
<id name="Id">
    <generator class="guid.comb" />
</id>

    <natural-id>
        <property name="Code" not-null="true" />
    </natural-id>
    <property name="Description" not-null="true" />
    <many-to-one name="Group" column="ID_Group" not-null="true" fetch="join" />
    <property name="ExpiryDate" />
    <list name="Tags" table="Items_Tags">
        <key column="ID_Item" />
        <index column="Idx" />
        <element column="Tag" />
    </list>
</class>

Выполнение запроса вызывает исключение NullReferenceException. При удалении последнего условия в дизъюнкции исключение не выбрасывается.

Я не избавился от этого без использования волшебных строк.


person Marcello    schedule 31.08.2012    source источник
comment
.Add(Restrictions.On(() =› tag).IsInsensitiveLike(searchKey, MatchMode.Start)) тег в этой строке должен быть tag.Tag, потому что вы определили псевдоним таблицы Tags как тег, но не упомянули поле в поиске   -  person Deepesh    schedule 31.08.2012
comment
тег представляет собой простой объект String. У него нет свойства Tag.   -  person Marcello    schedule 31.08.2012


Ответы (2)


Недавно я не проверял, но, насколько я знаю, NHibernate не поддерживает запросы к коллекциям значений напрямую с использованием API QueryOver или Criteria.

Я бы предложил, чтобы ваш лучший обходной путь - использовать SQLCriteria:

        var tagCriteria = new SQLCriterion(
            new SqlString("{alias}.Id IN (SELECT ID_Item FROM Items_Tags WHERE Tag LIKE ?)"),
            new[] {searchKey + "%"},
            new[] {NHibernateUtil.String}
            );

        session
            .QueryOver<Item>(() => i)
            .JoinAlias(x => x.Group, () => g, JoinType.InnerJoin)
            .Where(
                new Disjunction()
                    .Add(Restrictions.On(() => p.Description).IsInsensitiveLike(searchKey, MatchMode.Anywhere))
                    .Add(Restrictions.On(() => g.Description).IsInsensitiveLike(searchKey, MatchMode.Start))
                    .Add(tagCriteria)
            )
            .Take(maxResults)
            .Future();
person Martin Ernst    schedule 31.08.2012
comment
Спасибо. Не знаю почему, но как только я добавляю критерий в дизъюнкт, запрос вообще не выполняется, без исключений. Это происходит, даже если SqlCriterium определен следующим образом (без толку, но должно работать): new SQLCriterion(new SqlString({alias}.Id = ?), new[] {searchKey + %}, new[] {NHibernateUtil. Нить}); - person Marcello; 03.09.2012
comment
@Marcello Вместо новой SqlString попробуйте SqlString.Parse . - person xanatos; 01.11.2012
comment
@Marcello new SqlString не анализирует строку в поисках параметров, это делает SqlString.Parse. - person xanatos; 01.11.2012

используйте это, пожалуйста, поправьте меня, если я неправильно понял

session
    .QueryOver<Item>(() => i)
    .JoinAlias(x => x.Group, () => g, JoinType.InnerJoin)
    .JoinAlias(x => x.Tags, () => tag, JoinType.LeftOuterJoin) //left outher join because it is possible for an item to have no tags at all.
    .Where(
        new Disjunction()
            .Add(Restrictions.On(() => p.Description).IsInsensitiveLike(searchKey, MatchMode.Anywhere))
            .Add(Restrictions.On(() => g.Description).IsInsensitiveLike(searchKey, MatchMode.Start))
            .Add(Restrictions.On(() => tag.Tag).IsInsensitiveLike(searchKey, MatchMode.Start)) //this condition throws an exception
    )
    .Take(maxResults)
    .Future();
person VIRA    schedule 31.08.2012
comment
На самом деле тег — это строка. У него нет свойства Tag. - person Marcello; 31.08.2012
comment
вы указали Теги как тег, и вы должны использовать свойство Tags.Tag для его поиска. Вы пробовали код? - person VIRA; 31.08.2012
comment
Я попробовал ваш код. Он не компилируется. тег — это просто объект String. Я также попытался заменить свой тег () => на () => i.Tags. В этом последнем случае запрос к БД вообще не запускается, и возвращается пустой набор результатов без каких-либо исключений. Извините, если я не понял вашего предложения. Постарайтесь быть более точным. - person Marcello; 31.08.2012