2010-08-24 21 views
7

Estoy teniendo dificultades para obtener la sintaxis LINQ .. ¿Cómo puedo hacer este comando de una mejor manera?Haciendo una consulta LINQ mejor

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; 

Como puede ver, hay un usuario de tabla, un pintouser de tabla y un pin de tabla. Pintouser hace referencia al usuario y al pin. ¿Es posible escribir algo corto como "user.pintouser.pin"? Creo que tengo todas las propiedades de navegación configuradas, pero no estoy seguro de cómo usarlas correctamente o si podría mejorarlas modificándolas.

Gracias por leer

+0

Probablemente podría volver a escribir esto como una sola consulta. – leppie

Respuesta

8

Uso une a reescribir todo como una sola consulta limpio. Si leo sus preguntas correctamente, esto debe dar el resultado correcto:

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(); 

Tenga en cuenta, sin embargo, que si esta consulta devuelve otra cosa que un solo resultado su código será una excepción.

Si desea manejar la posibilidad de obtener una o ninguna fila, entonces debe usar SingleOrDefault().

Si desea manejar la posibilidad de obtener cualquier cantidad de filas, entonces realmente debería usar FirstOrDefault().

+0

Guau, eso fue rápido. ¡Gracias, funciona y esto me dio una idea de cómo usar join! – Phil

+0

La consulta original devuelve un solo pin. El suyo devuelve un IQueryable o algo así. – recursive

+0

@recursive - Tienes razón, estaba concentrado en las uniones y olvidé la llamada a Single(). Fijo. –

2

Debe usar join, como señala @JustinNiessner, pero esta es otra forma de escribir su consulta.

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

Ya que tiene propiedades de navegación, puede ser que también utilizarlos:

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

¿qué hace el comando "let"? – Phil

+0

como podría declarar una variable dentro de un bucle, creando una variable por iteración de bucle ... "let" le permite declarar una variable para cada fila en la consulta. –

3

Tenga en cuenta que si usted tiene establecer su relación de clave externa Righ en su base de datos, LINQ to SQL deben tener la se une de forma automática:

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

que significa que puede reducir esto a:

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

(ACTUALIZACIÓN Nota: en principio había sugerido lo siguiente, que es mucho más corto, pero creo que hará que dos viajes de ida y vuelta a la base de datos)

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

Ahora, el .pintouser.pin es seguro, ya que la Single() siempre devolverá un objeto user (o lanzará una excepción).