将您的第二个功能更改为:
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 to SQL 一起工作得很好,但它不能作为延迟查询的一部分执行。ToList()
在 Linq 查询末尾添加会导致它立即评估结果,而不是尝试将 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 to SQL 怎么可能成功地把你where
变成一个实际的数据库查询?
Linq 对这个类一无所知DO_RoleInfo
。它不知道如何向后映射——在某些情况下,这甚至是不可能的。当然,您可能会查看这段代码并说“哦,这很简单,只需在列中搜索 'Administrator' 或 'Executive' Name
”,但您是唯一知道这一点的人。 就 Linq to SQL 而言,查询纯属无稽之谈。
想象一下有人给了你这些指示:
去超市把制作莫顿汤普森火鸡的原料带回来。
除非你以前做过,而且大多数人没有做过,否则你对该指令的反应很可能是:
你可以去市场,你可以通过名称获得特定的成分,但你不能在你在那里的时候评估我给你的条件。我必须首先“取消映射”标准。我必须告诉你,这是我们制作这个食谱所需的原料——现在去拿吧。
总而言之,这并不是Linq to 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()
使用or实现结果ToArray()
并针对本地列表编写更多条件。
不要尝试使用 AutoMapper 或任何其他工具来隐藏 Linq 向 SQL 公开的真实实体。域模型是您的公共接口。您编写的查询是您私有实现的一个方面。了解差异并保持良好的关注点分离非常重要。