Linq to entities:一对多选择多对多

时间:2014-12-02 07:32:15

标签: c# entity-framework linq-to-entities

我有这个域名:

public class User
{
    public long Id { get; set; }
    public string Login { get; set; }
    public string Password { get; set; }
}

public class Application
{
    public long Id { get; set; }
    public string Name { get; set; }
}

public class UserApplications
{
    [ForeignKey("User")]
    public long UserId { get; set; }
    public User User { get; set; }

    [ForeignKey("Application")]
    public long ApplicationId { get; set; }
    public Application Application { get; set; }

    public DateTime LastConnection { get; set; }
}

我想做一个返回类似的选择:

List of select new
{
    User = user,
    Applications = applications // List of all user's applications
}

我试试:

from u in Users
join ua in UserApplications on u.Id equals ua.UserId into userApplications
from ua in userApplications.DefaultIfEmpty()
join a in Applications on ua.ApplicationId equals a.Id into applications
select new
{
    User = u,
    Applications = applications
}

但是这会将用户重复到每个应用程序。

我知道我可以在两个选择语句中执行此操作,但我不希望这样。

我该怎么做?

3 个答案:

答案 0 :(得分:2)

我不记得Entity Frameworks是否可以基于实体对象本身groupby(并在场景后面提取它Id并替换适合的东西等);但是这段代码适用于这种情况:

var q = from uapp in cntxt.UserApplications
        group uapp by uapp.UserId
            into g
            select new { UserId = g.Key, Applications = g.Select(x => x.Application) };

如果您愿意提取User

var q2 = from uapp in cntxt.UserApplications
            group uapp by uapp.UserId
                into g
                let u = Users.First(x => x.Id == g.Key)
                select new { User = u, Applications = g.Select(x => x.Application) };

假设您正在针对实体框架上下文编写查询 - 而不仅仅是尝试执行Linq to Objects查询。

答案 1 :(得分:1)

试试这个:

var tmp =
    from u in Users
        join ua in UserApplications on u.Id equals ua.UserId
        join a in Applications on ua.ApplicationId equals a.Id
    select new
        {
            User = u,
            App = a
        };
var res = tmp
    .ToArray() // edited
    .GroupBy(_ => _.User)
    .Select(_ => new 
        {
            User = _.Key, 
            Applications = _.Select(_ => _.App).ToArray()
        });

答案 2 :(得分:1)

实际上,您只需对用户设置的UserApplications实体进行分组:

context
    .UserApplications
    .GroupBy(_ => _.User, _ => _.Application)
    .ToList();

因为,实际上,IGrouping<User, Application>是您所需要的(Key是用户,而组项是他的应用程序。)

任何其他改进都是品味问题,比如投射到匿名类型:

context
    .UserApplications
    .GroupBy(_ => _.User, _ => _.Application)
    .Select(_ => new
    {
        User = _.Key,
        // since IGrouping<User, Application> is IEnumerable<Application>,
        // we colud return a grouping directly
        Applications = _  
    })
    .ToList();

(另一个投影选项会抛弃Applications中的组密钥):

context
    .UserApplications
    .GroupBy(_ => _.User, _ => _.Application)
    .Select(_ => new
    {
        User = _.Key,
        Applications = _.Select(app => app)
    })
    .ToList();