DTO命名约定,建模和继承

时间:2013-09-16 18:12:33

标签: c# nhibernate dto

我们正在使用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; }
    }

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

1)Just Id和Name    2)身份证,姓名和地址    3)身份证,姓名,地址和账户

我创建了一组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 个答案:

答案 0 :(得分:11)

建议你应该为每个实体设置一个DTO课程 后缀为DTO ,例如CustomerEntryDTO Customer 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模式中的 more ,请参阅以下文章:

Data Transfer Object

MSDN

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

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

答案 1 :(得分:0)

  

我如何使用插入和更新?

  1. 服务运营通常与业务运营密切相关。商务语言并不代表&#34;插入&#34;和&#34;更新&#34;,服务也没有。

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

  3.   

    我是否要创建另一个DTO?

    是的,您应该创建另一个DTO。

    有时服务运营合同可能已足够,无需为特定操作定义单独的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需要更多时间来编写,但更容易维护。

答案 2 :(得分:-1)

从第1项开始,对于插入和更新,最好使用命令模式。根据CQRS,您不需要DTO。考虑这个架构: CQRS — basic patterns 通过blogs.msdn.com