2010-08-24 5 views
7

Мне сложно получить LINQ-синтаксис .. Как я могу сделать эту команду лучше?Выполнение запроса LINQ лучше

var user = (from u in context.users 
      where u.email.Equals(email) 
      select u).Single(); 
var pinToUser = (from ptu in context.pintousers 
       where ptu.user_id.Equals(user.id) 
       select ptu).Single(); 
var pin = (from p in context.pins 
      where p.idpin.Equals(pinToUser.pin_idpin) 
      select p).Single(); 

return pin; 

Как вы можете видеть, что есть пользователь таблица, таблица pintouser и стол контактный. Pintouser ссылается на пользователя и штырь. Можно ли написать что-то короткое, как «user.pintouser.pin»? Я думаю, что у меня есть все свойства навигации, но я не уверен, как правильно их использовать или если я смогу улучшить их, изменив их.

Спасибо за чтение

+0

Возможно, вы могли бы переписать это как один запрос. – leppie

ответ

8

Использования присоединяется переписать все, как один чистый запрос. Если я читаю ваши запросы правильно, это должно дать вам правильный результат:

var pin = (from u in context.users 
      join ptu in context.pintousers on u.id equals ptu.user_id 
      join p in context.pins on ptu.pin_idpin equals p.idpin 
      where u.email == email 
      select p).Single(); 

Имейте в виду, однако, что если этот запрос возвращает ничего, кроме одного результата ваш код будет сгенерировано исключение.

Если вы хотите обработать возможность получения одной или нет строк, вы должны использовать SingleOrDefault().

Если вы хотите обработать возможность получения любого количества строк, вы должны действительно использовать FirstOrDefault().

+0

Ничего себе, это было быстро. Спасибо, это работает, и это дало мне некоторое представление об использовании соединения! – Phil

+0

Исходный запрос возвращает один вывод. Ваш возвращает IQueryable или некоторые из них. – recursive

+0

@recursive - Вы правы, я сосредоточился на объединениях и забыл вызов Single(). Исправлена. –

2

Вы должны использовать join, как указывает @JustinNiessner, но это еще один способ написать ваш запрос.

var user = context.users.Single(u => u.email == email); 
var pinToUser = context.pintousers.Single(ptu => ptu.user_id == user.id); 
var pin = context.pins.Single(p => p.idpin == pinToUser.pin_idpid); 
1

Поскольку у вас есть навигационные свойства, мог бы также использовать их:

Pin pin = 
(
    from u in context.Users 
    where u.email == email 
    from ptu in u.pintousers 
    let p = ptu.pin 
    select p 
).Single(); 
+0

Что делает команда «let»? – Phil

+0

, поскольку вы можете объявить переменную внутри цикла, создав одну переменную для каждой итерации цикла ... «let» позволяет объявлять переменную для каждой строки в запросе. –

3

Обратите внимание, что если у вас есть внешний ключ отношение установить RIGH в вашей базе данных, Linq к Sql должна иметь присоединяется к вам автоматически:

var pin = (from u in context.users 
     where u.email == email 
     select u.pintouser.pin).Single(); 

, который означает, что вы можете уменьшить это:

var pin = context.users.Where(u=>u.email == email) 
         .Select(u=>u.pintouser.pin) 
         .Single(); 

(ОБНОВЛЕНИЕ Примечание: Я первоначально предложил следующее, что намного короче, но я считаю, что это вызовет два круглых поездки в базу данных)

var pin = context.users.Single(u=>u.email == email).Single().pintouser.pin; 

Теперь .pintouser.pin безопасен, так как Single() всегда будет возвращать объект user (или исключение).