实体框架 – DDD,实体框架,聚合实体行为(Person.AddEmail等)

这里是一个简单的例子,我正在运行的问题不在于这里提供的一些想法和其他关于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 – 它足够聪明,以确定自从上次持续存在以来发生了什么变化.很难说实体框架如何处理这个.

相关文章

迭代器模式(Iterator)迭代器模式(Iterator)[Cursor]意图...
高性能IO模型浅析服务器端编程经常需要构造高性能的IO模型,...
策略模式(Strategy)策略模式(Strategy)[Policy]意图:定...
访问者模式(Visitor)访问者模式(Visitor)意图:表示一个...
命令模式(Command)命令模式(Command)[Action/Transactio...
生成器模式(Builder)生成器模式(Builder)意图:将一个对...