通过在Linq和EF中按条件连接表来获取详细信息

问题描述 投票:0回答:1

我的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    |
+----------------------------------+------------+-----------+-------+

我正在使用Entity Framework来获取此数据,并在我的代码中获取上下文类中的实体(如下所示)。

我的问题是:如何为所有产品生成所需的输出。我下面的代码无法获取我想要的所有数据。问题是结果中没有显示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();
c# sql-server entity-framework linq
1个回答
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,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的好处在于代码更简单,更自然,它看起来更像您的需求文本而不是(组)连接。此外,如果涉及两个以上的表(组)连接往往看起来很可怕。

我不会尝试使用GroupJoin提供解决方案。我相信其他答案会显示出来。比较并亲眼看看哪种解决方案似乎更容易理解。

© www.soinside.com 2019 - 2024. All rights reserved.