Поиск строки с соответствующими отношениями с использованием HQL - PullRequest
1 голос
/ 28 сентября 2010

Я использую Castle ActiveRecord и NHibernate.

У меня есть класс Instance , который имеет отношение "многие ко многим" с классом Component . Я хотел бы найти экземпляр, который связан с конкретным набором компонентов. Это возможно в HQL (или в NHibernate)?

Версия этой функции для linq:

public Instance find(IEnumerable<Component> passed_components)
{
    return Instance.Queryable.Single(i => passed_components.All(x => i.Components.Contains(x)));
}

Конечно, реализация NHibernate linq не может справиться с этим.

Я могу написать HQL, чтобы сделать это для одного из компонентов:

Instance.FindOne(new DetachedQuery("from Instance i where :comp in elements(i.Components)").SetParameter("comp", passed_components.First()));

Но похоже, что в сравнивает только один элемент с набором, он не может сравнивать набор с набором.

EDIT:

Это лучшее, что я мог сделать:

IQueryable<Instance> q = Queryable;
foreach(var c in components) {
    q = q.Where(i => i.Components.Contains(c));
}

Но это очень неэффективно. Он добавляет вложенный выбор в запрос SQL для каждого предложения where. Неоправданно длинный отбор в этом. Он объединяет таблицу Instance, таблицу соединения Instance / Component и таблицу Component. Требуется только таблица соединения экземпляра / компонента.

Из-за характера моих данных я собираюсь реализовать гибридное решение. Сузьте экземпляры в запросе, затем используйте linq для объектов, чтобы получить правильный, если это необходимо. Код выглядит так:

IQueryable<Instance> q = Queryable;
foreach(var c in components.Take(2)) {
    q = q.Where(i => i.Components.Contains(c));
}

var result = q.ToArray();
if(result.Length > 1) {
    return result.SingleOrDefault(i => !components.Except(i.Components).Any());
}
else return result.FirstOrDefault();

У кого-нибудь есть способ получше?

1 Ответ

1 голос
/ 28 сентября 2010

При использовании поставщика NHibernate.Linq должно работать следующее:

var passed_components = new List<Component>();
var instance = session.Linq<Instance>()
                      .Where(i => !passed_components.Except(i.Components).Any())
                      .SingleOrDefault();

Вы можете скачать провайдера здесь и узнать больше об этом здесь и здесь .

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