Я использую 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();
У кого-нибудь есть способ получше?