使用group进行简单的linq查询以返回一对多关系

时间:2012-08-26 20:05:59

标签: c# asp.net linq

我有一个用户数据表和另一个user_ratings表。它是一对多关系,因此它们由UserId连接,用户表是主键,user_ratings具有外键关系。每个user_ratings都有一个名为rating_value的列,其中填充了一个int,negative或positive,并将它们汇总在一起计算为用户的评级。我希望能够根据给定评级的日期为每个用户提取评级。这是我到目前为止我的linq声明,但我不认为这是正确的。

var profiles = from userprofs in Ent.UserProfiles
               join userratings in Ent.UserRatings on userprofs.UserId equals userratings.UserId
               where userratings.DateAdded >= drm.Start
               group userprofs by userprofs.UserId into g
               select new { ... };

不确定从哪里开始,我不确定我是否正确使用该组。我希望以后能够遍历此集合,以便能够根据user_ratings的总和显示每个用户及其相关评级

2 个答案:

答案 0 :(得分:2)

如果您希望了解有关评级的所有信息是汇总信息(总和,平均值,计数等),那么您可以执行以下操作:

var profiles = from userprof in Ent.UserProfiles
  join userrating in Ent.UserRatings on userprofs.UserId equals userratings.UserId
  where userrating.DateAdded >= drm.Start
  group userrating by userprof into g
  select new {g.Key.UserID, g.Key.UserName, Count = g.Count(), Avg = g.Avg(r => r.RatingValue) };

请注意,我将复数更改为单数名称,因为我们根据每个单独的项目定义linq查询(UserProfiles是复数,userprof每个项目都在“in”中)。

这对SQL有一个很好的直接转换:

SELECT up.userID, up.userName, COUNT(ur.*), AVG(ur.ratingValue)
FROM UserProfiles up JOIN UserRatings ur
ON up.userID = ur.userID
WHERE dateAdded > {whatever drm.Start is}
GROUP BY up.userID, up.userName

如果我们希望能够进入个人评级,这与单个SQL查询不太匹配,我们可以这样做:

var profiles = from userprof in Ent.UserProfiles
  join userrating in Ent.UserRatings on userprofs.UserId equals userratings.UserId
  where userrating.DateAdded >= drm.Start
  group new{userrating.RatingValue, userrating.SomeThing} by new{userprof.UserID, userprof.UserName};

这会给我们一个IEnumerable<Grouping<{anonymous object}, {anonymous object}>>我们可以迭代,在每次迭代时获得一个新的Key.UserIDKey.UserName,并且能够反过来获得{{1} }}和item.RatingValue(我为了演示而加入了,如果我们只想要一个item.SomeThing的值),就像这样:

IEnumerable<Grouping<{anonymous object}, int>>

然而,问题是,这个映射到的单个SQL查询不是很好。 Linq会尽力而为,但这意味着执行几个查询,所以你最好帮忙解决:

foreach(var group in profiles)
{
  Console.WriteLine("The user is :" + group.Key.UserName + " (id: " + group.Key.UserID ")");
  foreach(var item in group)
  {
    Console.WriteLine(item.SomeThing + " was rated " + item.RatingValue);
  }
}

它具有与以前相同的输出,但是转换为SQL允许进行单个查询,其余工作在内存中完成。 99%的时间,将一些工作拖入内存这样会降低效率,但由于之前没有一个可以映射到的SQL查询,这是一个例外。

答案 1 :(得分:0)

如果我理解你的问题:

from userprofs in Ent.UserProfiles
join userratings in Ent.UserRatings on userprofs.UserId equals userratings.UserId
where userratings.DateAdded >= drm.Start
group new{userprofs,userratings} by userprofs.UserId into g
select new { userId=g.Key, userRating=g.Sum(i=>i.userratings.rating_value) };

GroupBy会返回IEnumerable IGroupingIGrouping基本上是IEnumerable,具有额外的Key属性,其中包含用于进行分组的属性。如果您Sum分组rating_value,那么就在那里。