【问题标题】:Get details by joining tables with group by condition in Linq and EF通过在 Linq 和 EF 中按条件加入表来获取详细信息
【发布时间】:2018-08-25 15:41:24
【问题描述】:

我的 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();

【问题讨论】:

  • 能否请您也发布您收到的错误消息?谢谢
  • 嗨 PiJei 感谢您的关注,我没有收到任何错误或异常,但是我没有得到不包含产品 4 详细信息的所需输出
  • 我刚刚注意到,在您的评级表中,您没有产品 id 4 的条目,这可能是原因。
  • 是的,您是对的,对于该产品,我需要在输出结果中提到的评级为 0.0
  • 那么你需要一个完整的外连接来保留所有键,而不是进行内连接,

标签: c# sql-server entity-framework linq


【解决方案1】:

所以你有一个Products 的表,一个Ratings 的表和一个Images 的表。

每个Product 有零个或多个Ratings,每个Rating 使用外键ProductId 恰好属于一个Product。同样,每个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 的好处是代码更简单、更自然,与(组)连接相比,它看起来更类似于您的需求文本。此外,如果涉及两个以上的表(组)连接往往看起来很糟糕。

我不会尝试使用GroupJoin 提供解决方案。我相信其他答案会显示这一点。比较一下,看看哪种解决方案似乎更容易理解。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-08
    • 1970-01-01
    • 1970-01-01
    • 2018-10-25
    • 1970-01-01
    • 2020-09-14
    • 1970-01-01
    • 2012-06-02
    相关资源
    最近更新 更多