我应该将实体(持久)对象转换为 DTO 对象吗?
Posted
技术标签:
【中文标题】我应该将实体(持久)对象转换为 DTO 对象吗?【英文标题】:Should I transform Entity (Persistent) objects to DTO objects? 【发布时间】:2017-04-04 21:21:51 【问题描述】:我的项目分层如下:-
DAL (Entity)
--> BLL (DTO)
--> ApplicationComponent (ViewModel)
.
将有多个应用程序组件 (ApplicationComponent
) 将访问 BLL
。组件包括 Windows 服务、Web 服务、Web API 和 MVC 控制器。
我正在将NHibernate
Entity
对象转换为DTO
对象,同时将它们从DAL
传递给BLL
。在将此状态传递给ApplicationComponent
时,BLL
再次将其转换为ViewModel
。
这有助于我区分关注点以及数据在每一层中的处理方式。我不赞成返回 NHibernate
Entity
对象查看,原因如下:-
UI
,我想隐藏(或仅在需要时才公开),例如密码、用户类型、权限等。
在引用/连接上,NHibernate
会在访问属性时执行额外的查询,从而使延迟加载的使用无效。
向用户(Entity
)公开不必要的数据会造成错误的混淆和空白。
持久性实现泄漏到BLL
/UI
。 Entity
不是为 UI
设计的。它不能在所有情况下都为UI
提供服务。
我们使用DTO
属性上的属性来验证用户输入,这与Entity
看起来很奇怪。
我在使用这种方法时面临以下问题:-
最大和最明显的问题是具有相似成员和功能的冗余对象。 我必须在每一层中编写映射器方法来转换对象。这可以通过使用AutoMapper
或类似的东西来最小化;但它并不能完全解决问题。
问题:-
-
这是不是过度分离,应该避免(至少最小化)?
如果这种方法是正确的,我看不出有任何简单的方法可以完全绕过我上面提到的两个问题。请提出建议。
如果此方法不正确,请提出更正建议。
参考资料:-
-
Link1 建议将
Entity
对象转移到视图中,这在我看来不是一个好主意。
Link2 建议将 Entity
映射到我已经在做的 DTO
。
Link3 没有帮助。
Link4 建议使用类似自动映射工具之类的工具,这是可以的。但还是没有彻底解决问题。
Link5 是很棒的帖子。它解释了为什么我同意这些应该分开。它没有评论如何最大限度地减少由此造成的开销。
Link6 又没用了。
Link7 是一个很好的答案,它建议使用 Entity
,就像在 UI
中一样如果可能。它仍然不适用于我的大部分项目。
Linl8 是另一个很好的资源,它建议像我现在做的那样以两种方式进行映射。它仍然没有建议最小化开销的方法。
【问题讨论】:
...所以,我(团队)投入了大量时间来映射数百个对象......并创建一个域。它似乎正在工作..只需将其从服务器移动到 UI 并返回......很多人互相保证 - 重新映射到 DTO 是一种方式.. 我不明白。即使使用 automapper .. 集合/引用也将是挑战。虽然:Newtonsoft.Json(解析器、实体和数组值提供者)的覆盖很少……而 JSON 序列化/反序列化正在解决所有问题。没有 DTO,没有新对象...只是托管 JSON 化... 【参考方案1】:nhibernate 是允许您避免拥有 DAL 实体的那些 orm 之一,避免从 BLL 到 DAL 的额外映射会更好地提高性能,但如果它对您来说并不重要,最好保留让应用层松散耦合
【讨论】:
【参考方案2】:您是否考虑过在 DTO 和实体之间创建共享接口?您不应该将您的 ORM 与应用程序的其余部分紧密耦合。或者实际上尽可能使用它们之间的接口以外的任何东西。
理论上,您可以拥有一个单独的项目,该项目仅包含您期望传递的合同/抽象。为了最大限度地减少映射开销并使其对扩展开放,您可以确保实体按预期实现接口(省略不需要的部分),并且在您需要定制 DTO 的情况下,您可以使用接口创建具有映射的模型.
添加额外的接口项目时会产生一些开销,但从长远来看,它会让您的代码更整洁、更易于维护。
namespace Data
public class FakeRepo : IFakeRepo
public IThisIsAnEntity GetEntity()
return new ThisIsAnEntity();
public class ThisIsAnEntity : IThisIsAnEntity
public string HiddenField get; set;
public long Id get; set;
public string SomeField get; set;
public string AnotherField get; set;
namespace Data.Abstractions
public interface IFakeRepo
IThisIsAnEntity GetEntity();
namespace Abstractions
public interface IThisIsAnEntity : IThisIsAnSlimmedDownEntity
string SomeField get; set;
public interface IThisIsAnSlimmedDownEntity
long Id get; set;
string AnotherField get; set;
namespace Services.Abstractions
public interface ISomeBusinessLogic
IThisIsAnEntity GetEntity();
IThisIsAnSlimmedDownEntity GetSlimmedDownEntity();
namespace Services
public class SomeBusinessLogic : ISomeBusinessLogic
private readonly IFakeRepo _repo;
public SomeBusinessLogic(IFakeRepo repo)
_repo = repo;
public IThisIsAnEntity GetEntity()
return _repo.GetEntity();
public IThisIsAnSlimmedDownEntity GetSlimmedDownEntity()
return _repo.GetEntity();
namespace UI
public class SomeUi
private readonly ISomeBusinessLogic _service;
public SomeUi(ISomeBusinessLogic service)
_service = service;
public IThisIsAnSlimmedDownEntity GetViewModel()
return _service.GetSlimmedDownEntity();
public IComposite GetCompositeViewModel()
var dto = _service.GetSlimmedDownEntity();
var viewModel = Mapper.Map<IThisIsAnSlimmedDownEntity, IComposite>(dto);
viewModel.SomethingSpecial = "Something else";
return viewModel;
public class SomeViewModel : IComposite
public long Id get; set;
public string AnotherField get; set;
public string SomethingSpecial get; set;
namespace UI.Abstractions
public interface IComposite : IThisIsAnSlimmedDownEntity, ISomeExtraInfo
public interface ISomeExtraInfo
string SomethingSpecial get; set;
【讨论】:
以上是关于我应该将实体(持久)对象转换为 DTO 对象吗?的主要内容,如果未能解决你的问题,请参考以下文章
我应该将 DTO 映射到客户端和服务器端的域实体/从域实体映射吗?