我的SQL Server数据库中有以下3个表定义:
+----------------------------------+-----------------+------------------------------------------------
| Product | Rating | Image |
+----------------------------------+-----------------+-------------------------------------------------
| ProductId | Id | Id |
| ProdctName | Rating | Image |
| | ProductId FK References(Product)| ProductId FK References(Product)|
+----------------------------------+-----------------+---------------+----------------------------------
这些表包含以下示例数据:
+----------------------------------+------------
|Product | ProductId |ProductName |
+----------------------------------+------------
| | 1 |Prodcuct 1 |
| | 2 |Prodcuct 2 |
| | 3 |Prodcuct 3 |
| | 4 |Prodcuct 4 |
+----------------------------------+------------+
+----------------------------------+----------------------+
|Rating | Id |RatingVal |ProductId |
|+----------------------------------+-----------------------
| | 1 |3 |1 |
| | 2 |2 |2 |
| | 3 |3 |2 |
| | 4 |5 |3 |
| | 5 |4 |3 |
+---------------------+------------+------------+----------+
+----------------------------------+----------------------+
|Image | Id |ImagePath |ProductId
+----------------------------------+-----------------------
| | 1 |ABC |1 |
| | 2 |XYZ |2 |
| | 3 |LMN |3 |
| | 4 |PQR |4 |
+---------------------+------------+------------+----------+
我需要在一个地方收集有关产品的信息,以便每个产品都包含有关产品的详细信息(来自产品表),相关的平均评分(来自评分表)m和产品的图像路径(来自图像表) )。换句话说,我需要以下输出:
+----------------------------------+--------------------------------+
|Output | ProductId |ProductName |Avg(Rating)|ImgPath|
+----------------------------------+--------------------------------+
| | 1 |Prodcuct 1 |3 |ABC |
| | 2 |Prodcuct 2 |2.5 |XYZ |
| | 3 |Prodcuct 3 |4.5 |LMN |
| | 4 |Prodcuct 4 |0.0 |PQR |
+----------------------------------+------------+-----------+-------+
我正在使用实体框架来获取此数据,并在我的代码中获取上下文类中的实体(如下所示)。
我的问题是:如何为所有产品产生所需的输出。 我下面的代码无法获取我想要的所有数据。问题是结果中未显示具有id4的产品,我认为这是因为产品4在评级表中没有条目。
var trendingProducts = (from ratings in entities.Rating
group ratings by new { ratings.productId } into c
join products in entities.Products on c.FirstOrDefault().productId equals products.ProductID
join images in entities.Images on c.Key.productId equals images.ProductId
select new ProductViewModel
{
ProductId = products.ProductId,
ProductName = products.ProductName,
RatingVal = c.Average(l => l.RatingVal) == null ? 0 : c.Average(l => l.Rating),
ImagePath = images.ImagePath,
}).ToList();
答案 0 :(得分:0)
因此,您有一个Products
表,一个Ratings
表和一个Images
表。
每个Product
都具有零个或多个Ratings
,每个Rating
都使用外键Product
恰好属于一个ProductId
。同样,每个Product
都有零个或多个Images
,每个Image
都使用外键Image
恰好属于一个ProductId
。只是标准的一对多关系。
可能每个Product
都有零个或一个Image
:在这种情况下,您有一个零个或一对一的关系。代码将相似。主要区别在于“产品”不会有Images
的集合,而只会有一个虚拟的Image
。
如果您遵循entity framework code first conventions,您将拥有类似的课程:
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
,则实体框架将知道需要一个(组)联接。
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)join更类似于您的需求文本。此外,如果涉及两个以上的表(组),则联接看起来很可怕。
我不会尝试使用GroupJoin
给出解决方案。我相信其他答案也会显示出来。比较并亲自查看哪种解决方案似乎更容易理解。