2015-03-18 4 views
1

Я ищу чистый способ написать этот запрос Linq.Чистый способ написать этот запрос

В принципе, у меня есть коллекция объектов с идентификаторами, а затем с помощью nhibernate и Linq мне нужно проверить, имеет ли объект nhibernate коллекцию подкласса, где все коллекции идентификаторов находятся в коллекции подкласса nhibernate.

Если есть только один пункт, это будет работать:

var objectImCheckingAgainst = ... //irrelevant 
where Obj.SubObj.Any(a => a.id == objectImCheckingAgainst.Id) 

Теперь я хочу, чтобы вместо того, чтобы каким-то образом передать список objectImCheckingAgainst и возвращает истину, только если коллекция Obj.SubObj содержит все элементы в списке objectImCheckingAgainst основе на Id.

+0

Чтобы быть ясным, вам нужно «Obj.SubObj' иметь соответствующие идентификаторы для каждого элемента в 'objectImCheckingAgainst', но вы не заботитесь о другом? –

+0

@Matthew, точно. Obj.SubObj может иметь больше предметов. Я хочу проверить подмножество в objectImCheckingAgainst. –

ответ

1

Мне нравится использовать GroupJoin для этого.

return objectImCheckingAgainst.GroupJoin(Obj.SubObj, 
             a => a.Id, 
             b => b.id, 
             (a, b) => b.Any()) 
           .All(c => c); 

Я считаю, что этот запрос должен быть более или менее очевидны, но, по сути, это объединяет две коллекции с использованием их соответствующих идентификаторов в качестве ключей, а затем группы этих результатов. Затем для каждой из этих групп он определяет, существуют ли какие-либо соответствия. Наконец, он гарантирует, что все группы имеют совпадения.

Полезной альтернативой, которую я иногда использую, является .Count() == 1, а не .Any(). Очевидно, разница заключается в том, хотите ли вы поддерживать несколько элементов с одинаковым совпадением идентификаторов. Из вашего описания это звучало так, что это не имеет значения или принуждено другими средствами. Но это простая замена, в любом случае.

Важным понятием в GroupJoin, что я знаю, что это важно, но может или не может быть очевидным, является то, что первый перечислимы (который должен сказать, первый аргумент метода расширения или objectImCheckingAgainst в этом примере) будет иметь все его элементы включены в результат, а второй - или нет. Это не похоже на Join, где заказ не имеет значения. Если вы привыкли к SQL, это элементарные начала LEFT OUTER JOIN.


Другим способом вы могли бы сделать это, несколько более просто, но не так эффективно, было бы просто гнездятся запросы:

return objectImCheckingAgainst.All(c => Obj.SubObj.Any(x => x.id == c.Id)); 

Я говорю это потому, что это очень похоже на пример вы предоставили.

У меня нет опыта работы с NHibernate, но я знаю, что многие ORM (я считаю, что EF включены) будут сопоставлять это с SQL, поэтому эффективность может быть или не быть проблемой. Но в общем, мне нравится писать LINQ как можно ближе к параметру, так как он работает так же хорошо, как и в базе данных, поэтому я бы пошел с первым, о котором я говорил.

+0

Спасибо, действительно интересное дополнение к панели инструментов Linq. –

+1

Я сохраню ваш ответ как принятый, но стоит отметить, GroupJoin на момент написания не реализован в nhibernate (пока). Поэтому я использую обходной путь. –

1

Я не хорошо разбираюсь в LINQ-to-NHibernate, но при использовании LINQ для любого SQL-back всегда важно следить за сгенерированным SQL. Я думаю, что это где предложение ...

where Obj.SubObj.All(a => idList.Contains(a.id)) 

... будет производить лучший SQL (имеющий IN заявление).

idList - это список Id s, извлеченный из списка objectImCheckingAgainst объектов.