我们正在使用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”。 我认为这感觉有点多余。
很想听听你的想法
谢谢
答案 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 ,请参阅以下文章:
修改强>
如果您不希望通过网络发送某些属性(我知道您需要有条件地进行此操作,因此需要对此进行更多探讨),您可以使用{{3}等属性将它们从序列化机制中排除(但它仅适用于字段而不适用于属性,请参阅与属性一起使用的变通方法文章:NonSerialized
)。
您还可以创建自己的自定义属性,例如ExcludeFromSerializationAttribute
,并根据某些规则/条件将其应用于您不希望每次都通过网络发送的属性。 另见: NonSerialized on property
编辑2:
使用接口分隔一个CustomerEntryDTO
类中的不同属性。请参阅Google或MSDN上的界面分离原则。我稍后会尝试做一个示例解释。
答案 1 :(得分:0)
我如何使用插入和更新?
服务运营通常与业务运营密切相关。商务语言并不代表&#34;插入&#34;和&#34;更新&#34;,服务也没有。
客户管理服务可能会有一些Register
操作,该操作需要客户名称和其他一些可选参数。
我是否要创建另一个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。考虑这个架构: 通过blogs.msdn.com