2012-03-15 10 views
62

Estoy tratando de realizar un Únete entre varias tablas en LINQ. Tengo las siguientes clases:Cómo realizar la unión Une entre múltiples tablas en LINQ lambda

Product {Id, ProdName, ProdQty} 

Category {Id, CatName} 

ProductCategory{ProdId, CatId} //association table 

Y uso el siguiente código (donde product, category y productcategory son instancias de las clases anteriores):

var query = product.Join(productcategory, p => p.Id, pc => pc.ProdID, (p, pc) => new {product = p, productcategory = pc}) 
        .Join(category, ppc => ppc.productcategory.CatId, c => c.Id, (ppc, c) => new { productproductcategory = ppc, category = c}); 

Con este código puedo obtener un objeto de la clase siguiente:

QueryClass { productproductcategory, category} 

Dónde producproductcategory es de tipo:

ProductProductCategoryClass {product, productcategory} 

No entiendo que la unió "mesa" es, que estaba esperando una sola clase que contiene todas las propiedades de las clases involucradas.

Mi objetivo es poblar otro objeto con algunas propiedades que resultan de la consulta:

CategorizedProducts catProducts = query.Select(m => new { m.ProdId = ???, m.CatId = ???, //other assignments }); 

cómo puedo alcanzar este objetivo?

+0

No entendí ... ¿por qué ** m.ProdId = ??? ** en lugar de ** prodId = m.ProdId **? –

+0

Porque no sé de antemano cómo navegar y obtener ProdId – CiccioMiami

Respuesta

124

Para une, prefiero fuertemente consulta de sintaxis para todos los detalles que se esconden feliz (no menos importante de los cuales son la transparencia identificadores involucrados con las proyecciones intermedias en el camino que son evidentes en el equivalente de sintaxis de punto). Sin embargo, preguntaste sobre Lambdas, que creo que tienes todo lo que necesitas, solo tienes que ponerlo todo junto.

var categorizedProducts = product 
    .Join(productcategory, p => p.Id, pc => pc.ProdId, (p, pc) => new { p, pc }) 
    .Join(category, ppc => ppc.pc.CatId, c => c.Id, (ppc, c) => new { ppc, c }) 
    .Select(m => new { 
     ProdId = m.ppc.p.Id, // or m.ppc.pc.ProdId 
     CatId = m.c.CatId 
     // other assignments 
    }); 

Si es necesario, se puede ahorrar la unión en una variable local y reutilizarla más tarde, sin embargo, carecen de otros detalles por el contrario, no veo ninguna razón para introducir la variable local.

Además, se puede tirar la Select en el último lambda de la segunda Join (de nuevo, siempre que no haya otras operaciones que dependen de los resultados se inscribe), lo que daría:

var categorizedProducts = product 
    .Join(productcategory, p => p.Id, pc => pc.ProdId, (p, pc) => new { p, pc }) 
    .Join(category, ppc => ppc.pc.CatId, c => c.Id, (ppc, c) => new { 
     ProdId = ppc.p.Id, // or ppc.pc.ProdId 
     CatId = c.CatId 
     // other assignments 
    }); 

... y hacer un último intento de vender en la sintaxis de consulta, esto se vería así:

var categorizedProducts = 
    from p in product 
    join pc in productcategory on p.Id equals pc.ProdId 
    join c in category on pc.CatId equals c.Id 
    select new { 
     ProdId = p.Id, // or pc.ProdId 
     CatId = c.CatId 
     // other assignments 
    }; 

Sus manos pueden estar vinculados de si consulta de sintaxis está disponible. Sé que algunas tiendas tienen tales mandatos, a menudo basados ​​en la noción de que la sintaxis de consultas es algo más limitada que la sintaxis de puntos. Hay otras razones, como "¿por qué debería aprender una segunda sintaxis si puedo hacer todo y más en sintaxis de puntos?"Como muestra esta última parte, hay detalles que ocultan la sintaxis de consulta que puede hacer que valga la pena abrazar la mejora de la legibilidad que trae: todas esas proyecciones e identificadores intermedios que tiene que cocinar están felizmente no de frente y centro -etapa en la versión consulta de sintaxis - son pelusa fondo de mi caja de jabón ahora -.. de todos modos, gracias por la pregunta :)

+3

Gracias, su solución es más completa. Acepto que la sintaxis de la consulta en algunos casos es más clara, pero has acertado, se me ha pedido que use lambda. Además, tengo que hacer que esto se una a más de 6 tablas, y la notación de puntos en este caso es más clara – CiccioMiami

+0

+1 Perfecto ... !!! –

+0

@devgeezer ¿Qué sucede si necesitamos una condición adicional en la declaración 'JOIN'? ¿Como hacemos eso? Por ejemplo, en 'join pc in productcategory en la p.Id es igual a la línea pc.ProdId', necesitamos agregar' y p.Id == 1'. –

9

Lo que hemos visto es lo que obtienes - y es exactamente lo que usted pidió, aquí:

(ppc, c) => new { productproductcategory = ppc, category = c} 

Esa es una expresión lambda devolver un tipo anónimo con esas dos propiedades.

En sus CategorizedProducts, sólo tiene que ir a través de esas propiedades:

CategorizedProducts catProducts = query.Select(
     m => new { 
      ProdId = m.productproductcategory.product.Id, 
      CatId = m.category.CatId, 
      // other assignments 
      }); 
+0

Gracias. ¿Entiendo la discusión sobre la clase anónima pero sus propiedades contienen solo los objetos de clase que cumplen con la consulta? ¿Y qué sucede después de que realizo el 2 join? productproductcategory.product no está unido a la categoría ¿verdad? – CiccioMiami

+0

@CiccioMiami: Bueno, las propiedades son * referencias * a los objetos, sí. No está claro a qué se refiere con "no se unió": ¿qué información no obtiene de su consulta que quiere obtener? –

+0

Con la primera unión obtengo la unión entre productos y categoría de producto. Con el segundo, obtengo la unión entre categoría de producto (producto unido) y categoría. Eso significa que la información sobre la unión múltiple solo está contenida en productproductcategory. Esto significa que el producto (y la categoría) se acaban de unir con la categoría del producto. – CiccioMiami

3

toma vistazo a este código de ejemplo de mi proyecto

public static IList<Letter> GetDepartmentLettersLinq(int departmentId) 
{ 
    IEnumerable<Letter> allDepartmentLetters = 
     from allLetter in LetterService.GetAllLetters() 
     join allUser in UserService.GetAllUsers() on allLetter.EmployeeID equals allUser.ID into usersGroup 
     from user in usersGroup.DefaultIfEmpty()// here is the tricky part 
     join allDepartment in DepartmentService.GetAllDepartments() on user.DepartmentID equals allDepartment.ID 
     where allDepartment.ID == departmentId 
     select allLetter; 

    return allDepartmentLetters.ToArray(); 
} 

en este código me uní a 3 tablas y me uní a la condición de unión desde donde la cláusula

nota: las clases de Servicios son simplemente deformadas (encapsu tarde) las operaciones de la base de datos

1
public ActionResult Index() 
    { 
     List<CustomerOrder_Result> obj = new List<CustomerOrder_Result>(); 

     var orderlist = (from a in db.OrderMasters 
         join b in db.Customers on a.CustomerId equals b.Id 
         join c in db.CustomerAddresses on b.Id equals c.CustomerId 
         where a.Status == "Pending" 
         select new 
         { 
          Customername = b.Customername, 
          Phone = b.Phone, 
          OrderId = a.OrderId, 
          OrderDate = a.OrderDate, 
          NoOfItems = a.NoOfItems, 
          Order_amt = a.Order_amt, 
          dis_amt = a.Dis_amt, 
          net_amt = a.Net_amt, 
          status=a.Status, 
          address = c.address, 
          City = c.City, 
          State = c.State, 
          Pin = c.Pin 

         }) ; 
     foreach (var item in orderlist) 
     { 

      CustomerOrder_Result clr = new CustomerOrder_Result(); 
      clr.Customername=item.Customername; 
      clr.Phone = item.Phone; 
      clr.OrderId = item.OrderId; 
      clr.OrderDate = item.OrderDate; 
      clr.NoOfItems = item.NoOfItems; 
      clr.Order_amt = item.Order_amt; 
      clr.net_amt = item.net_amt; 
      clr.address = item.address; 
      clr.City = item.City; 
      clr.State = item.State; 
      clr.Pin = item.Pin; 
      clr.status = item.status; 

      obj.Add(clr); 



     } 
+1

Si bien este fragmento de código puede resolver la pregunta, [incluyendo una explicación] (http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) realmente ayuda a mejorar la calidad de su publicación.Recuerde que usted está respondiendo la pregunta a los lectores en el futuro, y es posible que esas personas no sepan los motivos de su sugerencia de código. –

Cuestiones relacionadas