Linq EF6:使用AutoMapper选择多个与运行时投影相同的左连接?
我试图简化一些实体框架代码,这些代码从“用户”开始投影,然后根据查询将各种其他表加入其中。其中一个查询查看所有用户,包括指示他们参与的程序(1或0)的数据,并返回UserProgram对象中的组合数据。它们是通过电子邮件地址关联的,而不是通过外键。目前看起来是这样的: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
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 :-)