域实体访问存储库

发布于 2024-11-18 03:17:32 字数 1015 浏览 3 评论 0原文

继续这些辩论:

DDD - 实体可以的规则t 直接访问存储库

实体可以访问存储库吗?

还有一些情况域访问存储库感觉更好。以这个例子为例,假设我需要数据库中的一个 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 对象,但在某些情况下这是不必要的,并且可能导致类爆炸。

无论如何,如果不是为了这类事情,为什么存储库接口存储在域中?

Continuing on from these debates:

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

Is it ok for entities to access repositories?

There are still some situations where it feels better for the Domain to access the repository. Take this example, which assumes I need a TaskStatus table in the database which contains a description for reporting purposes:

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);
    }
}

I know I could have CompletedTaskStatus and OpenTaskStatus objects but there are situations where this would be unnecessary and could lead to a class explosion.

And anyway, why are repository interfaces stored in the Domain, if not for this sort of thing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

凉宸 2024-11-25 03:17:32

实体可以访问存储库吗?

不,请不要这样做。

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

域应该完全不知道数据持久性,并且应该假设它是自动发生的。

ddd-the-repository-pattern。 aspx

其次,还有其他更实际的原因不将您的存储库注入您的实体中。

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

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

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

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

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

请参阅此处发布的图片:

DDD:应如何组织图层?

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<>的聚合根。它在聚合根级别起作用。

在 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);
    }    
}

Is it ok for Entities to access Repositories?

No. Please don't do this.

Firstly the idea of the Domain Model is to separate out the business logic from the application. Isolate it from your db, repositories and your application. This allows you to keep the business logic separate and to allow it to be tested and changed separate from your application.

The Domain should be completely unaware of data persistence, and should assume that it happens automagically.

ddd-the-repository-pattern.aspx

Secondly there's other more practical reasons not to inject your repositories into your enties.

  1. Your entites should be unit testable, by injecting your repositories into your entity you've created a dependency on your repository.

  2. Using a GetInstance() method breaks the Law of Demeter, you are creating a tight coupling of ITaskStatusRepository to your entity. Meaning that when creating a new Task and writing unit tests it is not obvious opon construction that a Task requires a ITaskStatusRepository. This makes it more difficult to unit test your business logic.

  3. From a DDD standpoint, a repository is not only concerned with interfacing with the DB, it could be retrieving from an in memory store. Or a List.

  4. Your repository does not have to be a 1 to 1 relationship with tables. If you need your task repository to perform inner joins with other tables to perform complex queries and it returns a list of Task items, then you expose a method from your repository that performs that query. (I think this is a common misconception of the repository pattern).

  5. Your entities should not be concerned with performing actions on the db.

Refer to the image posted here:

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";
    }
}

Inside the application layer, your repository is responsible for persistence (or not). A repository is a List<> of aggregate roots. And it works at the aggregate root level.

An example of using your Tasks inside a TaskService. A service acts upon Entities from your Application Layer.

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);
    }    
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文