改变你的第二个功能是:
public IEnumerable<DO_RoleInfo> SelectAll()
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return from role in _ctx.DB_RoleInfo.ToList()
select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}
AutoMapper只是罚款的LINQ到SQL,但它不能为递延查询的一部分来执行。在您的Linq查询的末尾添加ToList()
会导致它立即评估结果,而不是尝试将AutoMapper段作为查询的一部分进行翻译。
澄清
延迟执行(不“懒加载”)的概念没有任何意义,一旦你已经改变了结果类型的东西,这不是一个数据实体。考虑这两个类:
public class DB_RoleInfo
{
public int ID { get; set; }
public string Name { get; set; }
}
public class DO_RoleInfo
{
public Role Role { get; set; } // Enumeration type
}
现在考虑下面的映射:
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>
.ForMember(dest => dest.Role, opt => opt.MapFrom(src =>
(Role)Enum.Parse(typeof(Role), src.Name)));
这种映射是完全没问题的(除非我犯了一个错误),但让我们说你写的SelectAll
方法在你的原职而不是我的修订之一:
public IQueryable<DO_RoleInfo> SelectAll()
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return from role in _ctx.DB_RoleInfo
select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}
竟是那样的这个工作,但一个自称“可查询”,就在于。如果我尝试写下它,会发生什么情况:
public IEnumerable<DO_RoleInfo> SelectSome()
{
return from ri in SelectAll()
where (ri.Role == Role.Administrator) ||
(ri.Role == Role.Executive)
select ri;
}
想一想这件事真的很难。 Linq如何能够可能能够成功地将您的where
成为一个实际的数据库查询?
Linq对DO_RoleInfo
类一无所知。它不知道如何做映射落后 - 在某些情况下,这可能甚至不可能。当然,你可以看看这个代码,然后去“哦,这很简单,只需在Name
列”“中搜索'管理员'或'执行',但只有你是唯一知道这一点的人。就Linq to SQL而言,查询是纯粹的废话。
想象一下,有人给你这些指令:
Go to the supermarket and bring back the ingredients for making Morton Thompson Turkey.
除非你之前已经做到了,而且大部分人都没有,你到指令响应是最有可能将是:
你可以去市场,你可以通过名字来取得具体成分,但你不能评价我已经给你而你那边的条件。我必须“取消”标准第一个。我必须告诉你,这里是我们需要这个食谱的成分 - 现在去拿他们。
总之,这是不是LINQ的之间的一些简单不相容到SQL和AutoMapper。这两个图书馆都不是唯一的。不要紧实际操作中做映射到非实体类型 - 你可以很容易地做手工的映射,你仍然得到同样的错误,因为你现在给LINQ to SQL的一组不能再理解的指令,处理不具有任何特定实体类型的内在映射的神秘类。
这个问题到O/R映射的概念,并推迟执行查询的基础。甲投影是单向操作。一旦你的项目,你再也不能回到查询引擎,并说哦对了,这里为大家介绍一些多个条件。太晚了。你能做的最好的就是把它已经给你的东西和你自己评估额外的条件。
最后但并非最不重要的,我会给你一个解决方法。如果您希望能够从你的映射做唯一就是过滤行,你可以这样写:
public IEnumerable<DO_RoleInfo> SelectRoles(Func<DB_RoleInfo, bool> selector)
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return _ctx.DB_RoleInfo
.Where(selector)
.Select(dbr => Mapper.Map<DB_RoleInfo, DO_RoleInfo>(dbr));
}
这是处理映射为您和接受过滤器的实用方法在原实体,而不是的映射的实体。如果您有许多不同类型的过滤器,但始终需要执行相同的映射,则此功能可能会很有用。个人而言,我认为只要正确写出查询,首先确定需要从数据库中检索,然后进行任何预测/映射,然后最后如果需要做进一步过滤(你不应该),然后物化结果与ToList()
或ToArray()
并写入更多的条件对本地列表。
不要试图使用AutoMapper或任何其他工具来将Linq公开的实体隐藏到SQL中。领域模型是您的公共接口。您编写的查询是您的私有执行的一个方面。理解差异并保持良好的关注点很重要。
只是除了您的更新我的笔记回答:第二个版本的工作原理是因为Linq到SQL已经*知道*你已经做了一个不可逆转的预测; “SelectByKey”实际上只是将Linq用于对象。如果您检查正在生成的实际查询,我认为您会发现它仍然从数据库中选择所有实体,这相当于使用“ToList()”,然后过滤结果列表。 – Aaronaught 2010-02-06 15:33:57
这不是说AutoMapper支持LINQ。这是LINQ to SQL不支持AutoMapper。 LINQ to SQL查询提供程序查看表达式树以确定如何生成SQL查询。当它到达Mapper.Map部分时,它不知道如何生成SQL。 – 2010-02-07 18:11:15