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

时间:2016-11-21 13:03:08

标签: c# nhibernate orm mapping data-access-layer

我的项目分层如下: -

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 / UIEntity不适用于UI。在所有情况下都无法提供UI
  • 我们使用DTO属性上的属性进行用户输入验证,Entity看起来很奇怪。

我面临以下问题: -

  • 最大且明显的问题是具有相同功能的冗余对象。
  • 我必须在每一层中编写mapper方法来转换对象。这可以通过使用AutoMapper或类似的东西来最小化;但它没有完全解决问题。

问题: -

  • 这是否过度分离,应该避免(至少最小化)?
  • 如果这种方法是正确的,我没有看到任何简单的方法来完全绕过我上面提到的两个问题。请提出建议。
  • 如果此方法不正确,请提出更正建议。

参考文献: -

  1. Link1建议转移Entity个对象,以便查看我的理解并不是一个好主意。

  2. Link2建议将Entity映射到我已经同意的DTO

  3. Link3无效。

  4. Link4建议使用自动映射工具之类的东西。但它仍然没有完全解决问题。

  5. Link5很棒。它解释了为什么那些应该是分开的,我同意。它没有评论如何最小化由此引起的开销。

  6. Link6再次没用。

  7. 编辑1:

    我刚刚阅读了this优秀答案,建议在Entity 中使用UI,如果可能的话。它仍然不适用于我的大多数项目。

    编辑2:

    另一个优秀的post建议我现在正在进行双向映射。它仍然没有建议一种最小化开销的方法。

2 个答案:

答案 0 :(得分: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; }
    }
}

答案 1 :(得分:0)

nhibernate是使您避免拥有DAL实体的orm之一,它的性能最好避免从BLL到DAL的额外映射,但是如果对您而言并不重要,则最好保留使应用程序层松耦合