Итак, у вас есть таблица 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
. Я уверен, что другие ответы покажут это. Сравните и убедитесь сами, какое решение кажется более понятным.