域实体访问存储库

时间:2011-07-04 09:52:14

标签: architecture domain-driven-design repository-pattern ddd-repositories

继续这些辩论:

DDD - the rule that Entities can't access Repositories directly

Is it ok for entities to access repositories?

在某些情况下,域访问存储库感觉更好。假设我在数据库中需要一个包含用于报告目的的描述的TaskStatus表:

public class TaskStatus
{
    public long Id {get;set;}
    public string Description {get;set;}
}

public class Task
{
    public long Id {get;set;}
    public string Description {get;set;}
    public TaskStatus Status {get;set;}

    public void CompleteTask()
    {
        ITaskStatusReposity repository = ObjectFactory.GetInstace<ITaskStatusReposity>(); //Or whatever DI you do.
        Status = repository.LoadById(Constants.CompletedTaskStatusId);
    }
}

我知道我可以拥有CompletedTaskStatus和OpenTaskStatus对象,但是在某些情况下这可能是不必要的并且可能导致类爆炸。

无论如何,为什么存储库接口存储在域中,如果不存在这种情况呢?

1 个答案:

答案 0 :(得分:4)

实体可以访问存储库吗?

没有。请不要这样做。

首先,域模型的想法是将业务逻辑与应用程序分开。将其与数据库,存储库和应用程序隔离。这使您可以将业务逻辑分开,并允许它与您的应用程序分开进行测试和更改。

Domain应该完全没有意识到数据持久性,应该假设它是自动发生的。

ddd-the-repository-pattern.aspx

其次还有其他更实际的理由不将你的存储库注入你的内容。

  1. 您的entites应该是可单元测试的,通过将您的存储库注入您的实体,您已经创建了对您的存储库的依赖。

  2. 使用GetInstance()方法打破了Demeter法则,您正在创建ITaskStatusRepository与您的实体的紧密耦合。这意味着在创建新任务和编写单元测试时,任务需要ITaskStatusRepository并不是显而易见的构造。这使得对业务逻辑进行单元测试变得更加困难。

  3. 从DDD的角度来看,存储库不仅涉及与数据库的接口,它还可以从内存存储中检索。或列表。

  4. 您的存储库不必是与表的1对1关系。如果您需要任务存储库与其他表执行内部联接以执行复杂查询并返回任务项列表,那么您将从存储库中公开执行该查询的方法。 (我认为这是对存储库模式的一种常见误解)。

  5. 您的实体不应关心对数据库执行操作。

  6. 请参阅此处发布的图片:

    DDD: how the layers should be organized?

    public class TaskStatus
    {
       public long Id { get; set; }
       public string Description { get; set; }
    
       public TaskStatus() {
          Description = "Incomplete";
       }
    }
    
    public class Task
    {
        public long Id {get;set;}
        public string Description {get;set;}
        public TaskStatus Status {get;set;}
    
        public void CompleteTask()
        {        
            Status.Description = "Complete";
        }
    }
    

    在应用程序层内,您的存储库负责持久性(或不存在)。存储库是List&lt;&gt;聚集根。它在聚合根级别工作。

    在TaskService中使用您的任务的示例。服务作用于应用层的实体。

    public class TaskService 
    {
        private readonly ITaskRepository _taskRepository;
    
        public TaskService(ItaskRepository taskRepository){
          _taskRepository = taskRepository;
        }
    
        public List<Task> CompleteAllTasks()
        {
          List<Tasks> getTasks = _taskRepository.GetTasks();
          getTasks.ForEach(CompleteTask);
          return _taskRepository.Save(getTasks);
        }    
    }