我正在尝试简化一些实体框架代码,这些代码从“用户”投影,然后根据查询将各种其他表LEFT JOIN连接到它。其中一个查询查看所有用户,并包含指示他们参与的程序(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...
}
我想用AutoMapper替换对“new UserProgram”的调用,将两个对象组合成一个“DTO”对象,但我不知道是否可能。我见过的解决方案是使用.Project().To<UserProgram>()
来构造SELECT,但要求我可以在用户和程序之间导航。 (我没有将其设置为从用户导航到程序,因为两个表之间的关系有点特殊,并且与外键无关。)
有没有办法在不明确更新UserProgram对象的情况下执行此操作?显然,我无法直接调用Mapper.Map,因为这不会映射到Linq-to-Entities查询。
答案 0 :(得分:0)
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();
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 :-)
请测试一下,我现在没有VS,而且我在没有调试器的情况下编写它。如果某件事不起作用,请回答。