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

2024-02-24

我的项目分层如下:-

DAL (Entity) --> BLL (DTO) --> ApplicationComponent (ViewModel).

应用程序将有多个组件(ApplicationComponent)将访问BLL。组件包括 Windows 服务、Web 服务、Web API 和 MVC 控制器。

我正在转变NHibernate Entity反对DTO传递对象时DAL to BLL。当将此状态传递给ApplicationComponent, BLL再次将其转换为ViewModel.

这有助于我区分关注点以及每一层中数据的处理方式。我不赞成退货NHibernate Entity出于以下原因拒绝查看:-

  • 数据暴露于UI我想隐藏(或仅在需要时公开),例如密码、用户类型、权限等。
  • 关于引用/连接,NHibernate访问属性时执行额外的查询,从而使延迟加载无效。
  • 向用户(的Entity) 造成混乱和错误间隙。
  • 持久性实现泄漏到BLL/UI. Entity不是为UI。它无法服务UI在所有情况下。
  • 我们使用属性DTO用户输入验证的属性看起来很奇怪Entity.

我使用这种方法面临以下问题:-

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

问题:-

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

参考:-

  1. Link1 https://stackoverflow.com/questions/24261753/return-nhibernate-entity-from-web-api建议转Entity反对观点,在我看来这不是一个好主意。
  2. Link2 https://stackoverflow.com/questions/9819615/which-is-the-best-practices-for-exposing-entity-or-dto-to-view-in-mvc3建议绘制地图Entity with DTO我已经在做了。
  3. Link3 https://stackoverflow.com/questions/13176707/static-methods-to-transform-dto-to-entity没有帮助。
  4. Link4 https://stackoverflow.com/questions/7650616/how-to-map-persistent-objects-to-dto建议使用诸如自动映射器工具之类的东西,这是可以的。但仍然没有彻底解决问题。
  5. Link5 https://stackoverflow.com/questions/4865806/why-two-classes-view-model-and-domain-model?rq=1很棒的帖子。它解释了为什么这些应该分开,我同意。它没有评论如何最小化由此造成的开销。
  6. Link6 https://stackoverflow.com/questions/3094633/bestpractice-mixing-view-model-with-domain-model又没有帮助。
  7. Link7 https://stackoverflow.com/questions/18109547/orm-entities-vs-domain-entities-under-entity-framework-6-0是一个很好的答案,建议使用Entity正如在UI 如果可能的话。它仍然不适用于我的大部分项目。
  8. Linl8 https://stackoverflow.com/questions/2201150/should-i-map-a-dto-to-from-a-domain-entity-on-both-client-and-server-sides?rq=1是另一个优秀的资源,建议像我现在所做的那样继续以两种方式进行映射。它仍然没有提出一种最小化开销的方法。

您是否考虑过在 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; }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我应该将实体(持久)对象转换为 DTO 对象吗? 的相关文章

  • SetWindowsHookEx 函数返回 NULL

    我正在研究 DLL 注入 但收到错误如下 挂接进程失败 87 参数不正确 目标进程和dll都是64位的 注入代码为 BOOL HookInjection TCHAR target TCHAR dll name https msdn micr
  • C修改printf()输出到文件

    有没有办法修改printf为了将字符串输出到文件而不是控制台 我尝试在互联网上查找一些内容 发现了类似的电话dup dup2 and fflush这可能与此有关 EDIT 也许我不清楚 问题是这是C考试问题 问题如下 解释一个通常将字符串输
  • 为什么派生类不使用基类的operator=(赋值运算符)?

    以下是实际问题的简化版本 而不是打电话Base operator int 代码似乎生成了一个临时的Derived对象并复制它 既然函数签名似乎完美匹配 为什么不使用基本赋值运算符 这个简化的示例没有显示任何不良影响 但原始代码在析构函数中有
  • C# 中附加/分离事件处理程序的不同方式有什么区别

    我的问题有两个部分 首先 我们可以通过以下两种方式附加事件处理程序 myObject MyEvent new EventHandler MyHandler myObject MyEvent MyHandler 据我了解 这两者是等价的 在第
  • 通过引用传递时取消引用指针

    当通过引用传递给函数时取消引用指针时会发生什么 这是一个简单的例子 int returnSame int example return example int main int inum 3 int pinum inum std cout
  • rand() 播种与 time() 问题

    我很难弄清楚如何使用 rand 并使用 Xcode 用 time 为其播种 我想生成 0 到 1 之间的随机十进制数 该代码为我提供了元素 1 和 2 看似随机的数字 但元素 0 始终在 0 077 左右 有什么想法吗 我的代码是 incl
  • 将 C# 反射代码移植到 Metro-Ui

    我正在尝试移植使用反射的现有 C 类 通用工厂 但我无法编译这段代码 Type types Assembly GetAssembly typeof TProduct GetTypes foreach Type type in types i
  • C 中的模仿函数重写

    具体来说 函数重写能够调用基本重写方法 这有两部分 一个是预编译的库代码 1 另一个是库的用户代码 2 我在这里实现了一个尽可能最小的经典 Person 和 Employee 示例 非常感谢了解 OOP 概念的铁杆 C 开发人员的回应 我正
  • 使用反射获取基类的受保护属性值

    I would like to know if it is possible to access the value of the ConfigurationId property which is located in the base
  • 用 C# 制作 Vista 风格的应用程序

    我正在运行 Windows Vista 并且希望外观看起来像常规 Vista 程序 有没有关于如何构建 Vista 风格应用程序的真正好的教程 文章 我还想学习如何使用本机代码并将其转换为 C 如this http bartdesmet n
  • 如何使用泛型类型的 DataContractSerializer 编写自定义序列化器?

    我想编写一个自定义序列化器 用于将会话状态存储到Azure 缓存 预览版 这意味着这个自定义序列化器必须实现IDataCacheObjectSerializer 如果我错了 请告诉我 我需要编写这个自定义序列化程序的原因是我需要序列化一些包
  • Microsoft.Graph - 如何从具有不同用户名的共享邮箱发送?

    我目前正在将使用 SMTP 的服务代码移植到 Office 365 通过 SMTP 我可以使用 发件人 字段在来自共享收件箱的邮件上设置不同的用户名 同时保留共享电子邮箱地址 这似乎无法通过 Office 365 运行 其工艺流程为 客户填
  • c# 如何生成锦标赛括号 HTML 表

    所以我已经被这个问题困扰了三个星期 但我一生都无法弄清楚 我想做的是使用表格获得这种输出 演示 http www esl world net masters season6 hanover sc2 playoffs rankings htt
  • 更改其他页面的主窗口内容

    在 WPF 应用程序的主窗口中 我有一个 Badged 元素 来自材料设计 这是我的代码
  • C# 中处理 SQL 死锁的模式?

    我正在用 C 编写一个访问 SQL Server 2005 数据库的应用程序 该应用程序是数据库密集型的 即使我尝试优化所有访问 设置适当的索引等 我预计迟早会遇到死锁 我知道为什么会发生数据库死锁 但我怀疑我能否在某个时候发布不发生死锁的
  • realloc():重新分配为 char * 上的 strcat 腾出空间时下一个大小无效 [重复]

    这个问题在这里已经有答案了 我在以下代码中收到无效内存错误 printf s n FINE 5 printf s LENGTH IS d n FINE 6 strlen buffer char realloc buffer strlen b
  • 有没有更好的方法来获取每个项目与谓词匹配的子序列?

    假设我有一个 IEnumerable 例如 2 1 42 0 9 6 5 3 8 我需要获得与谓词匹配的项目的 运行 例如 如果我的谓词是 bool isSmallerThanSix int number 我想得到以下输出 2 1 0 5
  • C++ 标准中短语“构造函数没有名称”的含义

    在尝试理解 C 标准中的 构造函数没有名称 这句话时 我似乎在 clang 中发现了一个错误 有人可以证实这一点吗 VS2015 and gcc rejects this code and I think they it are is co
  • 展开路径中具有环境变量的文件名

    最好的扩张方式是什么 MyPath filename txt to home user filename txt or MyPath filename txt to c Documents and settings user filenam
  • c# 替代方案中 cfusion_encrypt 中填充的密钥是什么?

    我找到了从这里复制 C 中的 cfusion encrypt 函数的答案 ColdFusion cfusion encrypt 和 cfusion decrypt C 替代方案 https stackoverflow com questio

随机推荐