这里是一个简单的例子,我正在运行的问题不在于这里提供的一些想法和其他关于DDD的地方.
说我有一个ASP.NET MVC 3网站创建/操纵一个人.控制器访问应用程序服务层(PersonService),后者又使用域实体(EF 4 POCO)和PersonRepository进行更改并持久化.为了简单起见,我在这里省略了所有的界面.在这种情况下,人是根,为了简单起见,只有电子邮件地址(也假定电子邮件不是不可变的,可以更新).
选项1:
尝试坚持使用DDD的基础知识,其中与实体直接相关的行为实现为实体的一部分(Person实现AddEmail,ChangeEmail等).唯一的问题是,除了Add *方法之外,Person将需要知道上下文或实体框架(将删除任何持久性无知)或需要使用“服务”或存储库来标记电子邮件已修改.
// Person Service public class PersonService { // constructor injection to get unit of work and person repository... // ...methods to add/update a person public EmailAddress AddEmailAddress(int personId,EmailAddress email) { Person p = personRepository.Find(p => p.Id == personId).First(); p.AddEmail(email); uow.SaveChanges(); return email; } public EmailAddress ChangeEmailAddress(EmailAddress email) { Person p = personRepository.Find(p => p.Id == personId).First(); p.ChangeEmail(email); // change state of email object here so it's updated in the next line??? // if not here,wouldn't the Person entity have to know about the context // or use a service? uow.SaveChanges(); return email; } } // Person Repository public class PersonRepository { // generic repository implementation } // Person Entity public class Person { public string Name { get;set; } public IEnumerable<EmailAddress> EmailAddresses { get;set; } public void AddEmail(EmailAddress email) { this.EmailAddresses.Add(email); } public void ChangeEmail(EmailAddress email) { EmailAddress orig = this.EmailAddresses.First(e => e.Id == email.id); // update properties on orig // NOW WHAT? [this] knows nothing about the context in order to change state,etc,or do anything to mark the email add updated } } // Email public class EmailAddress { public string Email { get;set; } public bool IsPrimary { get;set; } }
选项二:
让个人服务使用存储库来添加/更新电子邮件地址,并且不对该实体执行行为.在许多关系(例如地址,两个表需要更新以完成工作)的情况下,这种情况要简单得多,但是模型就变成了一大堆的getter和setter.
// Person Service public class PersonService { // constructor injection to get unit of work and person repository... // ...methods to add/update a person public EmailAddress AddEmailAddress(int personId,EmailAddress email) { Person p = personRepository.Find(p => p.Id == personId).First(); personRepository.AddEmail(personId,email); uow.SaveChanges(); return email; } public EmailAddress ChangeEmailAddress(EmailAddress email) { personRepository.ChangeEmail(email); uow.SaveChanges(); return email; } } // Person Repository public class PersonRepository { // generic repository implementation } // Person Entity public class Person { public string Name { get;set; } public IEnumerable<EmailAddress> EmailAddresses { get;set; } } // Email public class EmailAddress { public string Email { get;set; } public bool IsPrimary { get;set; } }
无论如何,有什么想法吗?
谢谢Brian
选项1是要走的路.
推理是简单的 – 更改电子邮件地址是领域关注.我敢打赌你的域名专家说他们将需要更改电子邮件.自动将电子邮件更改的逻辑标记为应该在域模型中生活的业务逻辑.对象主要由他们的行为定义,而不是他们所持有的数据.
另外 – 在您选择使用工作单位之前,先考虑一下,并将所有服务都包装起来.总结根应该是绘制事务边界,如果服务器只包含存储库和域对象调用,服务通常是无用的.
我会有这样的事情:
public class Person{ public Email Email{get;private set;} public void SpecifyEmail(Email email){ //some validation,if necessary EnsureEmailCanBeChanged(); //applying state changes Email=email; //raising event,if necessary Raise(new EmailChanged(this)); } public class EmailChanged:Event<Person>{ public EmailChanged(Person p):base(p){} } } public class Email{ public Email(string email){ //validations (e.g. email format) Value=email; } //implicit to string,explicit from string conversions } public class PersonController{ public ActionResult SpecifyEmail(int person,string email){ _persons.Get(person).SpecifyEmail((Email)email); return RedirectToAction("Person",new{person}); } }
我正在使用NHibernate – 它足够聪明,以确定自从上次持续存在以来发生了什么变化.很难说实体框架如何处理这个.