首页 文章

DTO命名约定,建模和继承

提问于
浏览
29

我们正在使用AngularJS,C#,ASP.Net Web API和Fluent NHibernate构建Web应用程序 . 我们决定使用DTO将数据传输到表示层(角度视图) . 我对DTO的一般结构和命名有些怀疑 . 这是一个例子来说明我的场景 . 假设我有一个名为Customer的域名实体,它看起来像:

public class Customer
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual Address Address { get; set; }
        public virtual ICollection<Account> Accounts { get; set; }
    }

现在,在我的视图/表示层中,我需要检索不同类型的Customer,如:

1)Id Id和Name 2)Id,Name和Address 3)Id,Name,Address和Accounts

我创建了一组DTO来实现这个目标:

public class CustomerEntry
{
    public  int Id { get; set; }
    public  string Name { get; set; }
}

public class CustomerWithAddress : CustomerEntry
{
    public AddressDetails Address { get; set; }
}

public class CustomerWithAddressAndAccounts : CustomerWithAddress
{
    public ICollection<AccountDetails> Accounts { get; set; }
}

AddressDetails和AccountDetails是DTO,它们具有相应Domain实体的所有属性 .

这适用于查询和数据检索;问题是我将如何使用插入和更新 . 在创建新客户记录期间,名称和地址是强制性的,帐户是可选的 . 换句话说,我需要一个具有所有客户属性的对象 . 因此混淆:

1)我如何使用插入和更新? CustomerWithAddressAndAccounts DTO包含其中的所有内容,但其名称似乎有点难以用于插入/更新 .

2)我是否创建了另一个DTO ..如果我这样做,那不会重复,因为新的DTO将完全像CustomerWithAddressAndAccounts吗?

3)最后但并非最不重要的是,上面描述的DTO继承结构是否适合要求?有没有其他方法来模拟这个?

我已就这个主题发表过其他帖子,但未能取得多大进展 . 我拾取的一件事是避免在类名中使用后缀“DTO” . 我认为这感觉有点多余 .

很想听听你的想法

谢谢

3 回答

  • 11

    建议你应该为每个实体设置一个DTO类 suffixed with DTO 例如 CustomerEntryDTOCustomer entity (但您可以根据选择和要求使用继承层次结构) .

    而且,添加一个抽象的 DTOBase 类基类或接口;并且不要在每个地址,帐户和其他属性中使用这种深度继承的heirarchies包含在子DTO中 . 相反,将这些属性包含在同一个 CustomerEntryDTO 类中(如果可能),如下所示:

    [Serializable]
    public class CustomerEntryDTO : DTOBase, IAddressDetails, IAccountDetails
    {
        public  int Id { get; set; }
        public  string Name { get; set; }
        public AddressDetails Address { get; set; } //Can remain null for some Customers
        public ICollection<AccountDetails> Accounts { get; set; } //Can remain null for some Customemer
    }
    

    此外,您的DTO应该是可序列化的,以跨越流程边界 .

    有关DTO模式的更多信息,请参阅以下文章:

    Data Transfer Object

    MSDN

    Edit: 如果您不希望通过线路发送某些属性(我知道您需要有条件地进行此操作,因此需要对此进行更多探讨),您可以使用NonSerialized等属性将它们从序列化机制中排除(但是它仅适用于字段而非属性,请参阅与属性一起使用的变通方法文章:NonSerialized on property) . 您还可以创建自己的自定义属性,例如 ExcludeFromSerializationAttribute ,并根据某些规则/条件将其应用于您不希望每次都通过网络发送的属性 . Also see: Conditional xml serialization

    Edit 2: 使用接口分隔一个 CustomerEntryDTO 类中的不同属性 . 请参阅Google或MSDN上的界面分离原则 . 我稍后会尝试做一个示例解释 .

  • -1

    我如何使用插入和更新?

    • 服务运营通常与业务运营密切相关 . 商业语言不会说“插入”和“更新”,服务也不会 .

    • 客户管理服务可能会有一些 Register 操作,该操作需要客户名称和其他可选参数 .

    我会创建另一个DTO吗?

    是的,你应该创建另一个DTO .

    有时服务操作 Contract 可能就足够了,并且不需要为特定操作定义单独的DTO:

    function Register(UserName as String, Address as Maybe(of String)) as Response
    

    但大多数情况下,即使只有一个服务操作,最好定义一个单独的DTO类:

    class RegisterCommand
        public UserName as String
        public Address as Maybe(of String)
    end class
    
    function Register(Command as RegisterCommand) as Response
    

    RegisterCommand DTO可能与 CustomerWithAddress DTO非常相似,因为它具有相同的字段,但实际上这两个DTO具有非常不同的含义,并且不会相互替换 .

    例如, CustomerWithAddress 包含 AddressDetails ,而简单的 String 地址表示可能足以注册客户 .

    为每个服务操作使用单独的DTO需要更多时间来编写,但更易于维护 .

  • 0

    从项目1开始,对于插入和更新,它需要DTO . 考虑这个架构:
    CQRS — basic patterns
    来自blogs.msdn.com

相关问题