Automapper和Dapper在映射方面的区别

9
这个问题是为了验证当前实现是否符合最佳实践和性能要求。在之前的公司中,我一直使用Auto Mapper将关系对象映射到域模型实体和域模型实体映射到Dtos。ORM工具一直都是Entity framework。
在我的目前的公司,他们使用Dapper作为ORM工具,并且不使用AutoMapper,因为他们认为Dapper会在内部为您进行映射。所以他们构建了一个单独的类库项目,其中包含Dtos,并在DataAccess和Business层中引用了Dtos。
由Dapper返回的查询会被内部映射到Dtos。这些Dtos会返回给业务层,依此类推。
例如,在下面的代码中,Participant函数就是一个Dto。 DataAccess层的存储库文件:
 public List<ParticipantFunction> GetParticipantFunctions(int workflowId)
        {
            // Update the Action for Participant
            string selectSql = @"SELECT [WFPatFunc_ID] AS WFPatFuncID
                        ,[WFFunction]
                        ,[SubIndustryID]
                        ,[DepartmentID]
                    FROM [dbo].[WF_ParticipantsFunctions]
                    WHERE [DepartmentID] = (SELECT TOP 1 [DepartmentID] FROM [dbo].[WF] WHERE [WF_ID] = @workflowId)";

            return _unitOfWork.GetConnection().Query<ParticipantFunction>(selectSql, new
            {
                workflowId = workflowId
            }).ToList();
        }

开发人员告诉我,使用AutoMapper会增加开销并影响速度,而且Dapper内部已经有映射功能,因此不需要它。

我想知道他们所遵循的做法是否正确无误。


不,以下做法是错误的,原因如下:
  1. 数据库查询结果必须在实体中获取,然后转换为 DTO,我们不能直接将结果获取到 DTO 中。
  2. DTO 和实体都有不同的目的,DTO 可以与实体相比具有不同的列。
- Vijay Raheja
我认为,如果他们正在使用Dapper并创建视图并映射到DTO,那么Automapper就是一个负担。因为Automapper通常用于将实体与DTO / ViewModel进行映射。如果您认为Dapper映射的DTO不适合用作ViewModel,则AutoMapper将是创建“自动”ViewModel的好工具。 - jjchiw
1
@Tom 如果DTO是以json形式传递的,并且您不需要操作或创建ViewModel,我不认为在这种情况下使用Automapper有什么帮助。 @VijayRaheja 我认为获取所有实体,然后将它们转换为DTO就像开始使用它的第一步,但当您需要更高效的查询并创建一个“DTO”来返回时,最好是获取实体,然后将其转换为“DTO”并返回。 - jjchiw
"这样可以吗" (?) - 好的:它是否可行?它是否解决了他们需要解决的问题而不引入更糟糕的问题?如果是的话:是的! - Marc Gravell
也许问题在于名称DTO's,为什么不直接称之为TO's呢 :) - jjchiw
显示剩余4条评论
2个回答

20

在这里,没有对错之分。如果当前系统能够正常工作并满足所有需求,那太好了:就使用它!如果您真正需要自动映射器(auto-mapper)提供帮助的功能,那也很好:就使用它!

但是:如果您不需要自动映射器所做的事情(似乎他们确实不需要),那么就不要使用它呢?

也许一个关键点/问题是:如果您的要求以后发生变化,您重构代码的能力如何。对于许多人来说,答案是“当然,我们可以更改东西”-因此,在这种情况下,我会说:在实际需要额外层的要求出现之前,请暂时不要添加额外层。

如果您根本无法稍后更改代码,可能是由于存在大量面向公众的API(软件作为产品),则现在将所有内容解耦合(de-couple)使得公共API中没有耦合/依赖关系是有意义的。但是:大多数人并非如此。此外,dapper对于您的类型模型没有任何要求,除了:它必须看起来像表格。如果确实如此,那么,如果您不需要它,为什么要添加额外的层呢?


我最近发现的是,Dapper不能将数据映射到私有复杂对象中。它只适用于原始类型。你知道这是否属实吗?我正在尝试练习DDD,大多数情况下我的领域模型看起来并不像数据库表,而且我的领域模型大多会有带有复杂对象的私有设置器和私有构造函数。在这种情况下,Dapper的效果并不好。 - David Liang

12

这更像是一个架构问题,没有好与坏。

DTO的优点:

分层 - 您不直接使用数据对象,因此可以使用属性进行映射等操作,并且您的UI中不需要这些。这样,您可以将DTO存储在库中,该库不依赖于您的数据访问内容。(请注意,您也可以使用流畅的映射实现此目的,但这种方法可以使用您喜欢的方式

修改 - 如果您的领域模型发生更改,则公共接口将保持不变。假设您向模型添加属性,则已经构建的所有内容都不会出现在JSON中,因为没有理由加新字段。

安全性 - 这就是微软开始推动DTO的原因,如果我记得正确,我认为CodePlex(不确定是不是他们)在直接使用EF实体将内容添加到数据库。有人发现了这一点,并通过添加新的帖子扩展了JSON,他没有被允许访问其中的内容。例如,如果帖子引用了用户,则可以通过更改跟踪来添加一个新帖子以更改该用户的角色。虽然有方法可以保护您免受此类攻击,但安全性始终应该是选择退出而不是选择加入。

当我需要将BI级别公开到公共接口时,我喜欢使用DTO。例如,如果我有一个API,其中包含像api/Users/AllUsersapi/Users/GetFilteredUsers这样的系统操作。

无DTOs

性能 - 通常不使用DTO会更快。没有映射的额外步骤。投影可以帮助解决此问题,但在知道要执行什么操作时,您可以真正进行优化。

开发速度和更小的代码库 - 有时候,庞大的架构可能过于复杂,您只想完成任务。您并不想一直复制粘贴属性。

更灵活 - 这与安全性相反,有时您希望使用同一API执行多个操作。例如,如果您希望UI决定从一个大对象中看到什么内容,如选择和展开。(请注意,这可以使用DTO完成,但如果您尝试使用DTO进行展开,您就会知道它有多棘手)

当需要向客户端公开数据访问级别时,我会使用它,如果需要使用Breeze、JayData和/或Odata。使用像api/Usersapi/Users?filter=(a=>a.Value > 5)这样的API。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接