【问题标题】:Where do I put my mapping logic?我将映射逻辑放在哪里?
【发布时间】:2016-03-08 04:48:59
【问题描述】:

我有一个域模型、一个存储库和实体框架。我不希望我的域绑定到 EF 或一般的持久层。

因此,我创建了一个存储库以将 db.Users.Where(u => u.Team == "MyTeam") 之类的内容排除在我的域之外。

在实现通用存储库模式后,如果我想要特定团队中的用户列表,我使用UserRepository.GetUsersByTeam("MyTeam")

问题是我的 UserRepository 返回IEnumerable<EntityFrameworkUser>,而不是IEnumerable<DomainUser>,为了返回IEnumerable<DomainUser>,我需要将DomainUser 映射到某个地方的EntityFrameworkUser

那么,您具体在哪里从 EntityFrameworkUser 类映射到 DomainUser 类?

除了查询逻辑之外,存储库是否应该封装映射逻辑?

如果我想要一个域用户对象的集合,UserRepository.GetUsersByTeam("MyTeam") 的调用堆栈是什么样的?

搜索只找到了我通常引用 Martin Fowler 的一般回复。我需要一个具体的例子来参考。

【问题讨论】:

标签: c# entity-framework repository-pattern datamapper


【解决方案1】:

问题是我的 UserRepository 正在返回一个实体框架 User DbSet

这不应该是返回类型,因为这会引入耦合。您仍然可以返回该类型,但它应该被多态地解释为不同的类型。

所以虽然你可能在你的存储库中做这样的事情:

return db.Users;

返回类型不应该是那个实现类型(DbSet<User>?),而是更通用的东西:

public IQueryable<User> GetUsers()
{
    return db.Users;
}

整个域都在使用“EF 对象”,但域不知道也不关心这一点。该域将其视为User 模型的可查询集合。

【讨论】:

  • 为了清楚起见,我已经更新了问题。我返回的是 IEnumerable,而不是 DbSet。
  • @Legion:你有两个不同的User类型吗?一个用于 EF,一个用于域?在这种情况下,听起来您从根本上错误地使用了 EF。 EF 应该保留您的域对象。
  • 是的,我有两个。一个(用于 EF)用于持久层,并将 1 对 1 映射到数据库。另一个(用于域)包含我所有的业务逻辑,不是数据库用户表的镜像。
  • @Legion:如果你必须有两个,那么映射逻辑肯定属于持久层,因为它绑定到数据库结构。存储库接口中唯一对外可见的类型应该是域类型。但我强烈建议尽可能简单地使用 EF 来持久化您的域模型。
  • 问题是当我想切换到 nHibernate 或 Web 服务时会发生什么?我所有的业务逻辑都直接绑定到实体框架。
【解决方案2】:

如果您想单独保存域对象 - 单独保存它们。如果您的存储库从持久层返回对象,那么它为over-posting 问题打开了大门(当前端使用相同的对象时尤其危险)。我会将映射逻辑移到另一个类中并在您的存储库中使用它。

Automapper 是非常流行的库,用于映射不同的对象,例如域对象到 DTO,反之亦然。您可以将 Automapper 注入您的存储库并使用它将 IEnumerable&lt;EntityFrameworkUser&gt; 映射到 IEnumerable&lt;DomainUser&gt;。第一个寄存器映射

Mapper.CreateMap<EntityFrameworkUser, DomainUser>();

然后从您的存储库中调用它

return Mapper.Map<IEnumerable<EntityFrameworkUser>, IEnumerable<DomainUser>>(users);

【讨论】:

    【解决方案3】:

    如果所讨论的方法的目的只是始终返回指定团队的所有成员,并且您永远不会对结果应用附加子句,则可以更改 UserRepostory.GetUsersByTeam() 的返回类型方法从 EF DbSet&lt;User&gt; 类型改为List&lt;User&gt;,然后将return语句改为return db.Users.Where(u =&gt; u.Team == "MyTeam").ToList()

    您将不再从存储库级别获取 EF 对象。

    【讨论】:

    • 这将每次都实现整个列表,从而取消对结果枚举的延迟查询点。因此,如果有人调用 GetUsersByTeam() 并向其附加另一个子句,例如过滤到单个用户,它仍然会从该团队的数据库中获取 每个 用户。
    • 在我看来,GetUsersByTeam 方法的目的是返回团队中的每个用户,而这正是您所期望的。当然,这只是一个例子。
    猜你喜欢
    • 2012-01-22
    • 1970-01-01
    • 2014-03-16
    • 2013-07-26
    • 2018-06-14
    • 1970-01-01
    • 2011-09-08
    • 2015-01-22
    • 1970-01-01
    相关资源
    最近更新 更多