LINQ и подзапросы

#linq

#linq

Вопрос:

Как бы я сделал следующее в LINQ?

 select fkUniqueID
from tblUserRights
where fkUniqueID =
(select PkUserID
from Users
where UserID = 'mike')
  

Ответ №1:

Я предполагаю, что вы используете LINQ to SQL или что-то подобное.

В идеале, с объединением:

 var query = from user in db.Users
            where user.UserID == "mike"
            join userRight in db.UserRights
              on user.PkUiserID equals userRight.FkUniqueID
            select userRight;
  

В качестве альтернативы, если вы действительно хотите использовать подзапрос:

 var mikeIDs = from user in db.Users
              where user.UserID == "mike"
              select user.PkUserID;

var query = from userRight in db.UserRights
            where mikeIDs.Contains(userRight.fkUniqueID)
            select userRight;
  

(Обратите внимание, что LINQ является ленивым, поэтому это фактически не приведет к выполнению SQL-запроса для первой части.)

Конечно, если вы настроили свои связи, вы можете просто использовать:

 var rights = db.Users.Single(u => u.UserID == "mike").UserRights;
  

… это сработает, если такого пользователя не будет, и это, вероятно, вызовет два запроса к БД.

Комментарии:

1. Спасибо, но почему все же лучше использовать соединение?

2. @user517406: Это понятнее для чтения, ИМО. Для этого и существуют объединения.

Ответ №2:

Что-то вроде этого псевдо-LINQ должно сработать (это практически перевод проблемы)

 var uniqueIDs = from userRight in tblUserRights
                where fkUniqueID = (from user in Users 
                                    where user.UserID = 'mike' 
                                    select user.pkUserID).First()
                select userRight.fkUniqueID 
  

В SQL нам не нужно использовать ничего подобного First() конструкции ( Top 1 это был бы эквивалент SQL), потому что SQL попытается работать с нами, работая корректно, если есть только одна запись (или вообще никаких записей), и выдавая описательную ошибку, если есть две или более записей.

В C # это было бы переведено в ошибку времени компиляции, поскольку мы сравниваем с a T , а запрос возвращает a IEnumerable<T> .
First() явно возвращает первое значение T в коллекции или выдает ошибку, если в результате отсутствуют элементы.