Linq EF6:使用AutoMapper选择多个与运行时投影相同的左连接?

Linq EF6:使用AutoMapper选择多个与运行时投影相同的左连接?,linq,entity-framework,automapper,Linq,Entity Framework,Automapper,我试图简化一些实体框架代码,这些代码从“用户”开始投影,然后根据查询将各种其他表加入其中。其中一个查询查看所有用户,包括指示他们参与的程序(1或0)的数据,并返回UserProgram对象中的组合数据。它们是通过电子邮件地址关联的,而不是通过外键。目前看起来是这样的: public class User { public virtual int Id {get; set;} public virtual String Email {get; set;} //... } pu

我试图简化一些实体框架代码,这些代码从“用户”开始投影,然后根据查询将各种其他表加入其中。其中一个查询查看所有用户,包括指示他们参与的程序(1或0)的数据,并返回UserProgram对象中的组合数据。它们是通过电子邮件地址关联的,而不是通过外键。目前看起来是这样的:

public class User 
{
   public virtual int Id {get; set;}
   public virtual String Email {get; set;}
   //...
}

public class Programmember
{    
   public virtual int Id {get; set;}
   public virtual int Programid {get; set;}
   public virtual String Email {get; set;}
   //...
}

public IEnumerable<UserProgram> GetUsersWithProgram(int programid)
{
    IQueryable<User> userQueryable = ...
    var query = userQueryable
        .SelectMany(
            user=> ctx.ProgramMembers.Where(
                program => program.Email == user.Email
                    && program.programid == programid)
                .DefaultIfEmpty()), // LEFT JOIN                
                (user,program) => 
                     new UserProgram {
                          Email = user.Email,
                          Programname = program.Name
                          // lots of other fields...
                     }
公共类用户
{
公共虚拟整数Id{get;set;}
公共虚拟字符串电子邮件{get;set;}
//...
}
公共课计划成员
{    
公共虚拟整数Id{get;set;}
公共虚拟int程序ID{get;set;}
公共虚拟字符串电子邮件{get;set;}
//...
}
公共IEnumerable GetUsersWithProgram(int programid)
{
IQueryable userQueryable=。。。
var query=userQueryable
.SelectMany(
user=>ctx.ProgramMembers.Where(
program=>program.Email==user.Email
&&program.programid==programid)
.DefaultIfEmpty(),//左连接
(用户、程序)=>
新用户程序{
Email=user.Email,
Programname=程序名
//很多其他领域。。。
}
我想用AutoMapper替换对“new UserProgram”的调用,将两个对象合并为一个“DTO”对象,但我不知道这是否可行。我看到的解决方案是使用
.Project().to()
构造一个SELECT,但要求我可以在用户和程序之间导航。(我没有将其设置为从用户导航到程序,因为这两个表之间的关系有些特殊,没有外键关联。)

有没有一种方法可以在不显式新建UserProgram对象的情况下执行此操作?显然,我不能直接调用Mapper.Map,因为这不会映射到Linq to Entities查询。

您能尝试一下吗:

var query =     from c in userQueryable
                join program in ctx.ProgramMembers.Where(p=> p.programid == programid) ON c.Email    equals program.Email into joined
                from program in joined.DefaultOrEmpty()
                select new
                {
                    Email = c.Email,
                    ProgramName = program == null ? "(null)" : program.Name 
                };
或者您可以使用ToLookUp()


请测试它,我现在没有VS,我在没有调试器的情况下编写它。如果某个东西不起作用,请回答。

谢谢,但我认为使用ToLookup不会起作用,因为它无法映射到SQL查询。(例如,“LINQ to Entities无法识别该方法…get_Item(System.String)”)我不确定如何用AutoMapper投影来替换第一个解决方案中的“新”――它看起来相当于我已经拥有的……我认为我的方法是错误的。与其使用AutoMapper投影多个对象,更好的方法是使用表达式投影。
var ctx_lookUp = ctx.ProgramMembers.Where(p=>p.programid == programid).ToLookup(item => item.Email);

var query = from c in userQueryable
            select new
            {
               Email = c.Email,
               programName = ctx_lookup[c.Email].SingleOrDefault("(null)").Select(item=>item.Name)
            };

SingleOrDefault() - return one object or 0, if your database will have more that 1, then you will get exception :-)