Итак, у вас есть таблица Products, таблица Ratingsи стол Image.
Каждый из них Productимеет ноль или более Ratings, каждый из них Ratingпринадлежит только одному, Productиспользуя внешний ключ Image. Точно так же каждый Productимеет ноль или более ProductId, каждый из них Productпринадлежит точно одному Image, используя внешний ключ Images. Просто стандартные отношения «один ко многим».
Может быть, каждый Productимеет нуль-один Image: в этом случае у вас есть отношение «нуль-один-к-одному». Код будет аналогичным. Главное отличие состоит в том, что «Продукт» не будет иметь набор Image, он будет иметь только один виртуальный Image.
Если вы будете следовать первым правилам кода рамки сущности, у вас будут такие классы, как:
class Product
{
public int Id {get; set;}
// every Product has zero or more Ratings:
public virtual ICollection<Rating> Ratings {get; set;}
// every product has zero or more Images:
public virtual ICollection<Image> Images {get; set;}
... // other properties
}
class Rating
{
public int Id {get; set;}
// every Rating belongs to exactly one Product using foreign key:
public int ProductId {get; set;}
public virtual Product Product {get; set;}
...
}
class Image
{
public int Id {get; set;}
// every Image belongs to exactly one Product using foreign key:
public int ProductId {get; set;}
public virtual Product Product {get; set;}
...
}
Это все, что должна знать структура сущности, чтобы обнаружить ваши отношения «один ко многим». Он знает, какие таблицы / столбцы вам нужны, и он знает отношения между таблицами. Возможно, вам нужны разные идентификаторы для ваших таблиц или свойств. В этом случае вам понадобятся атрибуты или свободный API. Но это выходит за рамки этого вопроса.
Обратите внимание, что в инфраструктуре сущности все не виртуальные свойства станут столбцами в ваших таблицах. Все виртуальные свойства представляют собой отношения между таблицами.
Мне нужно собрать информацию о продукте в одном месте, чтобы каждый продукт содержал информацию о продукте (из таблицы продуктов), соответствующий средний рейтинг (из таблицы оценок) и путь изображения для продукта (из таблицы изображений).
Всякий раз, когда люди запрашивают «объекты со своим под-объектом», они стремятся создать (групповое) соединение. Однако, если вы используете структуру сущностей, гораздо проще использовать ICollectionsдля этих запросов. Если вы используете ICollection, Entity Framework будет знать, что требуется объединение (группа).
var result = myDbContext.Products // from the collection of Products
.Where(product => ...) // select only those Products that ...
.Select(product => new // from every remaining Product make one new
{ // object with the following properties:
// Select only the properties you actually plan to use!
Id = product.Id,
Name = product.ProductName,
...
AverageRating = product.Ratings // from all Ratings of this Product
.Select(rating => rating.Rating) // get the Rating value
.Average(), // and Average it.
Images = product.Images // from all Images of this product
.Select(image => image.ImagePath) // select the ImagePath
.ToList(),
// or if a Product has only zero or one Image:
Image = product.Image?.ImagePath // if the product has an Image, get its ImagePath
// or use null if there is no Image
});
Самое приятное в использовании ICollections - то, что код является более простым и более естественным, он выглядит более похожим на текст вашего требования, чем объединение (group). Кроме того, если задействовано более двух таблиц (групп), похоже, они выглядят ужасно.
Я не буду пытаться дать решение, используя GroupJoin. Я уверен, что другие ответы покажут это. Сравните и убедитесь сами, какое решение кажется более понятным.