Cómo realizar la unión entre varias tablas en LINQ lambda

Estoy intentando realizar una combinación entre varias tablas en LINQ. Tengo las siguientes clases:

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, obtengo un objeto de la siguiente clase:

 QueryClass { productproductcategory, category} 

Donde producproductcategory es de tipo:

 ProductProductCategoryClass {product, productcategory} 

No entiendo dónde está la “tabla” unida, esperaba una única clase que contiene todas las propiedades de las clases involucradas.

Mi objective es poblar otro objeto con algunas propiedades resultantes de la consulta:

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

¿Cómo puedo lograr este objective?

Para las uniones, prefiero fuertemente la syntax de consulta para todos los detalles que están felizmente ocultos (no menos importante son los identificadores transparentes involucrados con las proyecciones intermedias en el camino que son evidentes en el equivalente de syntax 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 = mcCatId // other assignments }); 

Si es necesario, puede guardar la unión en una variable local y volver a utilizarla más adelante, aunque no tenga otros detalles en contrario, no veo ninguna razón para introducir la variable local.

Además, puede lanzar Select en la última lambda de la segunda Join (de nuevo, siempre que no haya otras operaciones que dependan de los resultados de la combinación) 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 haciendo un último bash de venderle en la syntax de la 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 }; 

Tus manos pueden estar atadas a si la syntax de consulta está disponible. Sé que algunas tiendas tienen tales mandatos, a menudo basados ​​en la noción de que la syntax de consultas es algo más limitada que la syntax de puntos. Hay otras razones, como “¿por qué debería aprender una segunda syntax si puedo hacer todo y más en syntax de puntos?” Como muestra esta última parte, hay detalles que esconde la syntax 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 no son, afortunadamente, frontales y centrales. etapa en la versión de syntax de consulta – son de fondo. Fuera de mi caja de soap ahora, de todos modos, gracias por la pregunta. 🙂

Lo que has visto es lo que obtienes, y es exactamente lo que pediste, aquí:

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

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

En sus Productos Categorizados, solo necesita ir a través de esas propiedades:

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

mira este código de muestra de mi proyecto

 public static IList GetDepartmentLettersLinq(int departmentId) { IEnumerable 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 participé en una condición de unión desde donde cláusula

nota: las clases de Servicios simplemente están deformadas (encapsulan) las operaciones de la base de datos

  public ActionResult Index() { List obj = new List(); 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); } 
 var query = from a in d.tbl_Usuarios from b in d.tblComidaPreferidas from c in d.tblLugarNacimientoes select new { _nombre = a.Nombre, _comida = b.ComidaPreferida, _lNacimiento = c.Ciudad }; foreach (var i in query) { Console.WriteLine($"{i._nombre } le gusta {i._comida} y nació en {i._lNacimiento}"); }