如何使用 Linq 对两个以上的表进行分组

How to group more than two tables using Linq

我有三个表("Ratings"、"Comments" 和 "Users")。一个评级可以有多个评论。一条评论属于一个用户。

到目前为止,我的 LINQ 语句运行良好。

from rating in Ratings
join comment in Comments
on rating.ID equals comment.RatingID
join user in Users
on comment.UserID equals user.ID
select new {rating, comment, user}
.Where(x => x.rating.LocationID == 3);

如何分组?

这在一定程度上取决于您要分组的依据。但是有多种解决方案。

解决方案一:

假设您想按评分分组,那么您可以这样做:

var query1 = from rating in db.Ratings
                join comment in db.Comments
                    on rating.ID equals comment.RatingID
                join user in db.Users
                    on comment.UserID equals user.ID
                group new { comment, user } by rating into g
                select new { g.Key, l = g.ToList() };

foreach (var row in query1)
{
    // you get rows grouped by rating
    Debug.WriteLine(row.Key.ID); // rating.ID

    // and a list of comments/users per rating
    foreach (var g in row.l)
    {
        Debug.WriteLine(g.comment.ID);
        Debug.WriteLine(g.user.ID);
    }
}

这会为您提供每个评分一行。并且动态对象 g 包含每个评分 comment/user 对的列表。

方案二:

但是,就像@gertarnold 提到的那样,只读入要分组的对象会更容易。然后遍历它的属性。像这样:

var query2 = db.Ratings;

foreach (var rating in query2)
{
    Debug.WriteLine(rating.name);
    foreach (var comment in rating.Comments)
    {
        Debug.WriteLine(comment.name);
        Debug.WriteLine(comment.User.name);
    }
}

这更容易理解。它的性能缺点很严重,因为它对内部循环中的每个评论执行单独的数据库 SELECT 语句。如果评级有很多评论,那么这会很慢。使用分组的第一个示例将所有内容都拉入单个数据库 SELECT 语句中,这要快得多。

方案三:

并且有一种方法可以兼顾两种解决方案的优点。像解决方案 2 中那样做,并在其前面添加一些 DataLoadOptions

DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Rating>(rating => rating.Comments);
options.LoadWith<Comment>(comment => comment.User);
db.LoadOptions = options;

这将在单个 SELECT 中预加载所有评级和所有必要的子对象。它快速且易于阅读和理解。

PS: 附注:表应该以单数形式命名。在那种情况下 RatingCommentUser 而不是 RatingsCommentsUsers.

PS2:要在解决方案 1 中也获得没有评论的评级,您需要将连接转换为外部连接。像这样:

var query1 = from rating in db.Ratings
        join comment in db.Comments
            on rating.ID equals comment.RatingID into j1
        from comment in j1.DefaultIfEmpty()
        join user in db.Users
            on comment.UserID equals user.ID into j2
        from user in j2.DefaultIfEmpty()                                
        group new { comment, user } by rating into g
        select new { g.Key, l = g.ToList() };

另请参阅:101 LINQ Samples - Left outer join