Я пытаюсь выполнить соединение между несколькими таблицами в LINQ. У меня есть следующие занятия:
Product {Id, ProdName, ProdQty}
Category {Id, CatName}
ProductCategory{ProdId, CatId} //association table
И я использую следующий код (где product
, category
и productcategory
являются экземплярами вышеуказанных классов):
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});
С помощью этого кода я получаю объект из следующего класса:
QueryClass { productproductcategory, category}
Если категория продукта имеет тип:
ProductProductCategoryClass {product, productcategory}
Я не понимаю, где находится объединенная «таблица», я ожидал, что будет один класс , содержащий все свойства из задействованных классов.
Моя цель - заполнить другой объект некоторыми свойствами, полученными в результате запроса:
CategorizedProducts catProducts = query.Select(m => new { m.ProdId = ???, m.CatId = ???, //other assignments });
как я могу достичь этой цели?
Ответы:
Для соединений я настоятельно предпочитаю синтаксис запроса для всех деталей, которые удачно скрыты (не последней из которых являются прозрачные идентификаторы, связанные с промежуточными проекциями по пути, которые очевидны в эквиваленте точечного синтаксиса). Однако вы спросили о лямбдах, которые, я думаю, у вас есть все, что вам нужно - вам просто нужно все это собрать.
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 });
Если вам нужно, вы можете сохранить соединение в локальную переменную и повторно использовать его позже, однако, не имея других деталей, напротив, я не вижу причин для введения локальной переменной.
Кроме того, вы можете добавить
Select
в последнюю лямбду второгоJoin
(опять же, при условии, что нет других операций, зависящих от результатов соединения), что даст: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 });
... и сделав последнюю попытку продать вам синтаксис запроса, это будет выглядеть так:
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 };
Ваши руки могут быть связаны с тем, доступен ли синтаксис запроса. Я знаю, что у некоторых магазинов есть такие полномочия - часто на основании того, что синтаксис запроса несколько более ограничен, чем синтаксис точки. Есть и другие причины, например, «зачем мне изучать второй синтаксис, если я могу делать все и даже больше в точечном синтаксисе?» Как показывает эта последняя часть, есть детали, которые скрывает синтаксис запроса, которые могут сделать его достойным внимания с улучшением удобочитаемости, которое он приносит: все эти промежуточные проекции и идентификаторы, которые вам нужно приготовить, к счастью, не являются главными - этап в версии с синтаксисом запроса - это фоновая чушь. Сними мою мыльницу - в любом случае, спасибо за вопрос. :)
источник
JOIN
операторе? Как мы это делаем? Например, вjoin pc in productcategory on p.Id equals pc.ProdId
строке нам нужно добавитьand p.Id == 1
.p.Id == 1
поскольку это скорее фильтр where, чем критерий соединения. То , как вы бы сделать присоединиться к более чем одному критерию , как правило, чтобы использовать анонимный тип:join pc in productcategory on new { Id = p.Id, Other = p.Other } equals new { Id = pc.ProdId, Other = pc.Other }
. Это работает в Linq-to-Objects, и я предполагаю, что то же самое будет работать и с запросами к базе данных. С базами данных вы можете отказаться от сложных запросов на соединение, определив соответствующие внешние ключи и получив доступ к связанным данным через связанное свойство.Вы получаете то, что видели, и это именно то, о чем вы просили:
(ppc, c) => new { productproductcategory = ppc, category = c}
Это лямбда-выражение, возвращающее анонимный тип с этими двумя свойствами.
В ваших категориях продуктов вам просто нужно пройти через эти свойства:
CategorizedProducts catProducts = query.Select( m => new { ProdId = m.productproductcategory.product.Id, CatId = m.category.CatId, // other assignments });
источник
CatId
работает нормально. ИбоProdId
должно бытьm.productproductcategory.product.Id
ИЛИm.productproductcategory.productcategory.ProdId
. Эти два назначения различаются: первое относится к продукту (присоединено кproductcategory
), второе -productcategory
к обоимproduct
иcategory
. Вы понимаете мои рассуждения?взгляните на этот пример кода из моего проекта
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(); }
в этом коде я объединил 3 таблицы и выплюнул условие соединения из предложения where
примечание: классы Services просто искажают (инкапсулируют) операции с базой данных
источник
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); }
источник
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}"); }
источник
это было давно, но мой ответ может кому-то помочь:
если вы уже правильно определили отношение, вы можете использовать это:
var res = query.Products.Select(m => new { productID = product.Id, categoryID = m.ProductCategory.Select(s => s.Category.ID).ToList(), }).ToList();
источник