关于DDD,Repository Patterns和ORM,我有一个有点荒谬的问题.在这个例子中,我有3个类:Address,Company和Person.人是公司的成员并拥有地址.公司也有一个地址.
这些类反映了数据库模型.我删除了我的模型的任何依赖项,因此它们不依赖于特定的ORM库,如NHibernate或LinqToSql.这些依赖项在存储库中处理.
在其中一个存储库中有一个SavePerson(Person person)方法,它根据数据库中是否已存在来插入/更新 Person.
由于Person对象有公司,因此我在进行SavePerson调用时也会保存/更新Company属性的值.我在此过程中插入/更新公司的所有数据 - 名称和地址.
但是,我真的很难想到公司的数据在与人交往时可以改变的情况 - 我只希望能够将公司分配给一个人,或者将一个人转移到另一个公司.我认为我不想和新人一起创建新公司.因此SaveCompany调用会引入不必要的数据库调用.保存人员时,我应该能够更新CompanyId列.
但由于Person类具有Company属性,因此我有点倾向于使用它更新/插入它.从严格/纯粹的角度来看,SavePerson方法应该保存整个Person.
首选方式是什么?只需在保存人员或保存其所有数据时插入/更新公司财产的CompanyId?或者你会为两种场景创建两种不同的方法(你会给它们命名什么?)
另外,另一个问题是,我目前有不同的方法来保存人员,地址和公司,因此当我保存公司时,我也称为SaveAddress.假设我使用LinqToSql - 这意味着我不会在同一个Linq查询中插入/更新公司和地址.我猜有2个Select Calls(检查公司是否存在,检查地址是否存在).然后两个插入/更新调用.如果引入更多复合模型类,甚至更多.LinqToSql有没有办法优化这些调用?
public class Address { public int AddressId { get; set; } public string AddressLine1 { get; set; } public string AddressLine2 { get; set; } public string City { get; set; } public string PostalCode { get; set; } } public class Company { public int CompanyId { get; set; } public string Name { get; set; } public Address Address { get; set; } } public class Person { public int PersonId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public Company Company { get; set; } public Address Address { get; set; } }
编辑
另请参阅此后续问题.值对象如何存储在数据库中?
我自己最近使用了IRepository方法,Keith建议.但是,你不应该在这里专注于这种模式.相反,DDD手册中还有一些可以应用的部分.
首先,您可以在此处应用值对象(VO)的概念.在你的情况下,它将是地址.值对象和实体对象之间的区别在于实体具有标识; VO没有.VO的身份确实是它的属性的总和,而不是唯一的身份.在Domain-Drive Design Quickly(这也是一个免费的PDF下载)一书中,他通过声明地址实际上只是地球上的一个点并且不需要像人一样的单独的SocialSecurity身份来解释这一点.地球上的这一点是街道,数字,城市,拉链和国家的组合.它可以有纬度和经度值,但根据定义它们甚至是VO,因为它是两点的组合.
另外,不要忘记DDD剧本中的服务概念.在您的示例中,该服务将是:
public class PersonCompanyService { void SavePersonCompany(IPersonCompany personCompany) { personRepository.SavePerson(); // do some work for a new company, etc. companyRepository.SaveCompany(); } }
当您有两个需要类似操作来协调其他操作组合的实体时,需要服务.在您的情况下,保存Person()并同时创建一个空白Company().
现在,您将如何在数据库中保存地址VO?你会明显使用IAddressRepository.但由于大多数ORM(即LingToSql)要求所有对象都具有标识,因此这里的诀窍是:将标识标记为模型中的内部标识,因此它不会暴露在模型层之外.这是Steven Sanderson自己的建议.
public class Address { // make your identity internal [Column(IsPrimaryKey = true , IsDbGenerated = true , AutoSync = AutoSync.OnInsert)] internal int AddressID { get; set; } // everything else public [Column] public string StreetNumber { get; set; } [Column] public string Street { get; set; } [Column] public string City { get; set; } ... }