我应该将实体(持久化)对象转换为DTO对象吗?

6

我的项目分层如下:

DAL(实体) --> 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/UIEntity 没有为 UI 设计。它不能在所有情况下为 UI 提供服务。
  • 我们在 DTO 属性上使用属性进行用户输入验证,这在 Entity 中看起来很奇怪。

我遇到了以下问题:

  • 最大和明显的问题是具有类似成员和功能的冗余对象。
  • 我必须在每个层中编写映射器方法以转换对象。这可以通过使用 AutoMapper 或类似工具来最小化,但它并不能完全解决问题。

问题:

  1. 这是一种过度分离,应该避免(至少尽量减少)吗?
  2. 如果这种方法是正确的,我没有看到任何简单的方法来完全规避我上面提到的两个问题。请给出建议。
  3. 如果这种方法是不正确的,请给出纠正意见。

参考资料:

  1. Link1建议将Entity对象转移到视图中,但据我理解这并不是一个好主意。
  2. Link2建议使用DTO映射Entity,而我已经在做了。
  3. Link3没有帮助。
  4. Link4建议使用类似自动映射工具的东西,这还可以。但它仍然不能完全解决问题。
  5. Link5是很棒的文章。它解释了为什么它们应该分开,我也同意。但它没有评论如何最小化由此引起的开销。
  6. Link6再次没有帮助。
  7. Link7是一个很好的答案,建议在UI中尽可能使用原来的Entity。但它仍然不适用于我的大多数项目。
  8. Linl8是另一个很好的资源,建议像我现在做的那样进行双向映射。但它仍然没有建议减少开销的方法。

1
所以,我们(团队)投入了很多时间来映射数百个对象...并创建了一个域。似乎它正在工作中...只剩下将其从服务器移动到UI和返回...这么多人向彼此保证-重新映射为DTO是正确的方法...我不明白。即使使用自动映射器...集合/引用也将是挑战。然而:少量重写Newtonsoft.Json(解析器、实体和数组值提供程序)...和JSON序列化/反序列化就解决了所有问题。没有DTO,没有新的对象...只有受管理的JSON-ification... - Radim Köhler
2个回答

1
您是否考虑过在DTO和实体之间创建共享接口?不应该将ORM与应用程序的其余部分紧密耦合。如果可能的话,实际上除了它们之间的接口之外,不应该使用任何其他东西。理论上,您可以拥有一个单独的项目,仅保存您期望传递的内容的合同/抽象。为了最小化映射开销并使其开放以进行扩展,您可以确保实体按预期实现接口(省略不需要的内容),并且在需要定制DTO的情况下,您可以使用接口创建具有映射的模型。添加额外的接口项目时会有一些开销,但从长远来看,它将使您的代码更清晰,更易于维护。

enter image description here

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; }
    }
}


0

NHibernate是一种ORM,它允许您避免拥有DAL实体,并且避免从BLL到DAL进行额外的映射将更好地提高性能,但如果这对您来说不是关键,最好保持原样以使应用程序层松耦合。


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