如何使用LINQ将数据选择到一个对象中?

31

我有这样的数据:

UserId   |  SongId
--------   --------
1          1
1          4
1          12
2          95

我也有下面这个类:

class SongsForUser
{
    public int User;
    public List<int> Songs;
}

我想要做的是使用 LINQ 从我的数据中选择并创建一个 SongsForUser 对象集合。以下是我目前的代码:

var userCombos = songs.UserSongs.Select(x => new SongsForUser() { User = x.UserId, 
                                                                  Songs = /*What goes here?*/ });
我该如何填充我的“歌曲列表”?
结果应该是两个“SongsForUser”对象。 对于用户1,其“歌曲列表”中应有3个项目。 对于用户2,其“歌曲列表”中应有1个项目。
4个回答

46
songs.UserSongs.GroupBy(x => x.User).Select(g => new SongsForUser() 
{ 
    User = g.Key,
    Songs = g.Select(s => s.SongId).ToList()
});

2
为什么只在投影中选择歌曲ID,而不作为分组的一部分? - Jon Skeet
2
这里在 ToList 部分出现了错误。我认为这可能是因为这是 Linq to Entities。错误信息:LINQ to Entities 不识别方法 'System.Collections.Generic.List1[System.String] ToListString' 方法,且该方法无法转换为存储表达式。` - Abe Miessler
@AbeMiessler 确保你在顶部有 using System.Linq - Eren Ersönmez
不错。想出了类似的解决方案。+1 - Mare Infinitus
@AbeMiessler:如果一开始就提到LINQ to Entities就好了... - Jon Skeet
显示剩余2条评论

22

我猜你想要的是:

var songsByUser = songs.UserSongs
                       .GroupBy(song => song.UserId, song => song.SongId)
                       .Select(g => new SongsForUser { User = g.Key,
                                                       Songs = g.ToList() });
为了解释清楚,GroupBy之后你会得到一堆分组,每个分组的键是用户ID,而分组中的值是歌曲ID。
Key = 1, Values = 1, 4, 12
Key = 2, Value = 95
然后您只需将其转换为SongsForUser类型。请注意,在对象初始化程序中调用构造函数时,不需要显式包括() - 除非您需要指定构造函数参数,否则它是隐式的。 顺便说一句,您可以在一个GroupBy调用中完成所有操作:
var songsByUser = songs.UserSongs
         .GroupBy(song => song.UserId, song => song.SongId,
                  (user, ids) => new SongsForUser { User = user,
                                                    Songs = ids.ToList() });

就个人而言,我通常会觉得使用单独的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() };

编辑:上述方法是“提供程序中立”的,但似乎不适用于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() });

AsEnumerable方法会强制进行数据库中的分组操作,但最终的投影(包括ToList调用)会在本地完成。但是,您应该检查生成的SQL语句以确保效率。


1
假设你有以下内容:
public class SongsForUser
{
    public int UserId;
    public List<int> Songs;
}

那么像这样的一个函数就可以了。列表只是为了有一些数据来测试。

    public void Group()
    {
        List<Tuple<int, int>> SongRelations = new List<Tuple<int, int>>();

        SongRelations.Add(new Tuple<int, int>(1, 1));
        SongRelations.Add(new Tuple<int, int>(1, 4));
        SongRelations.Add(new Tuple<int, int>(1, 12));
        SongRelations.Add(new Tuple<int, int>(2, 95));

        var list = SongRelations.GroupBy(s => s.Item1)
                                .Select(r => new SongsForUser()
                                {
                                    UserId = r.Key,
                                    Songs = r.Select(t => t.Item2).ToList(),
                                });
    }

list 包含两个类型为 SongsForUser 的项目。 一个是用户 1,包含歌曲列表 1、4 和 12; 另一个是用户 2,包含歌曲列表 95。


0

在最简单的形式下,你只需要:

List<MapPoint> points = db.PropertyResearches.Where(a => a.deptId == 66).Select(x => new MapPoint { property = x.notes.Substring(0, 10), latitude = x.lat, longitude = x.@long }).ToList();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接