如何使用LINQ选择对象?

Abe*_*ler 27 .net c# linq linq-to-entities

我的数据看起来像这样:

UserId   |  SongId
--------   --------
1          1
1          4
1          12
2          95
Run Code Online (Sandbox Code Playgroud)

我也有以下课程:

class SongsForUser
{
    public int User;
    public List<int> Songs;
}
Run Code Online (Sandbox Code Playgroud)

我想做的是使用LINQ从我的数据中选择以创建SongsForUser对象的集合.以下是我到目前为止所提出的:

var userCombos = songs.UserSongs.Select(x => new SongsForUser() { User = x.UserId, 
                                                                  Songs = /*What goes here?*/ });
Run Code Online (Sandbox Code Playgroud)

我如何填写我的Songs清单?

所以结果应该是两个SongsForUser对象.对于用户1,它将在Songs列表中有3个项目.对于用户2,它将在Songs列表中有1个项目.

For*_*veR 38

songs.UserSongs.GroupBy(x => x.User).Select(g => new SongsForUser() 
{ 
    User = g.Key,
    Songs = g.Select(s => s.SongId).ToList()
});
Run Code Online (Sandbox Code Playgroud)

  • 为什么只在投影范围内而不是分组中选择歌曲ID? (2认同)
  • 这在`ToList`部分抛出了一个错误。我相信可能是因为这是Linq to Entities。错误:“ LINQ to Entities无法识别方法'System.Collections.Generic.List`1 [System.String] ToList [String](System.Collections.Generic.IEnumerable`1 [System.String])”方法,以及此方法不能转换为商店表达式。 (2认同)

Jon*_*eet 19

我怀疑你想要:

var songsByUser = songs.UserSongs
                       .GroupBy(song => song.UserId, song => song.SongId)
                       .Select(g => new SongsForUser { User = g.Key,
                                                       Songs = g.ToList() });
Run Code Online (Sandbox Code Playgroud)

为了解释,在GroupBy您将拥有一堆组之后,每个组的键是用户ID,并且组内的值是歌曲ID:

Key = 1, Values = 1, 4, 12
Key = 2, Value = 95
Run Code Online (Sandbox Code Playgroud)

然后你只是将它转换成你的SongsForUser类型.请注意,()在对象初始值设定项中调用构造函数时,不需要显式包含它 - 除非需要指定构造函数参数,否则它是隐式的.

顺便说一句,你可以在一个GroupBy电话中完成所有这些:

var songsByUser = songs.UserSongs
         .GroupBy(song => song.UserId, song => song.SongId,
                  (user, ids) => new SongsForUser { User = user,
                                                    Songs = ids.ToList() });
Run Code Online (Sandbox Code Playgroud)

就个人而言,我通常会发现一个单独的Select调用更具可读性.

您还可以使用查询表达式完成所有这些操作:

var songsByUser = from song in songs.UserSongs
                  group song.SongId by song.UserId into g
                  select new SongsForUser { User = g.Key, Songs = g.ToList() };
Run Code Online (Sandbox Code Playgroud)

编辑:以上是"提供商中立",但听起来它不适用于LINQ to Entities.您可能能够像这样工作:

var songsByUser = songs.UserSongs
                       .GroupBy(song => song.UserId, song => song.SongId)
                       .AsEnumerable()
                       .Select(g => new SongsForUser { User = g.Key,
                                                       Songs = g.ToList() });
Run Code Online (Sandbox Code Playgroud)

AsEnumerable调用将强制在数据库中完成分组,但最终投影(包括ToList调用)将在本地完成.您应该检查生成的SQL的效率.