相关疑难解决方法(0)

实体可以访问存储库吗?

我刚刚开始使用DDD,所以这可能是个愚蠢的问题......

是否可以让实体访问存储库(通过某个IRepository接口)在运行时获取值?例如,我想对属性强制执行"默认"选择:

class Person {
    private Company _employer;

    public Company Employer {
        get { return _employer; }
        set { 
            if(value != null) {
                _employer = value;
            } else {
                _employer = employerRepository.GetDefaultEmployer();
            }
        }
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,做这样的事情是对DDD原则的可怕违反.如果不是,我的下一个问题是提供存储库使用的最佳方式是什么?是否应该在创建Person对象时提供?

谢谢,P

domain-driven-design ddd-repositories repository-pattern

25
推荐指数
3
解决办法
7401
查看次数

DDD(域驱动设计),如何处理实体状态更改,以及封装需要处理大量数据的业务规则

public class Person
{
    public IList<String> SpecialBirthPlaces;
    public static readonly DateTime ImportantDate;
    public String BirthPlace {get;set;}

    public DateTime BirthDate
    {
        set
        {
            if (BirthPlace!=null && 
                value < ImportantDate && 
                SpecialBirthPlaces.Contains(BirthPlace))
            {
                BirthPlace = DataBase.GetBirthPlaceFor(BirthPlace, value);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是尝试在我的域模型中封装一个简单的规则.我试图捕获的规则是:当出于某种原因,我们更新一个人的出生日期(例如,原始用户输入中存在错误)时,我们需要检查该人的出生地并将其替换为来自其他人的其他值.数据库,如果它在我们的数据库中列为特殊的出生地.

但是,我实现它有两个问题:

  1. 此规则修改域实体状态(属性),我需要在用户界面中反映此更改.我的域名模型是POCO.我可以把这个逻辑放在ViewModel中,但这是错误的,因为它不是UI逻辑.这是我需要捕获的一个重要的域规则.

  2. 我的SpecialBirthPlaces列表非常大,每次我从数据库中获取客户时我都不想填充它.此外,当规则得到满足时,我需要替换Birthplace.正如我所说,特殊的出生地和替代品的列表非常大,并存储在数据库中.

如何在DDD风格中实现我需要的逻辑?

c# domain-driven-design

22
推荐指数
1
解决办法
6460
查看次数

领域驱动设计中的规范模式

我一直在努力解决与规范有关的DDD相关问题,我已经阅读了很多关于DDD和规范和存储库的内容.

但是,如果尝试在不破坏域驱动设计的情况下组合所有这三个,则会出现问题.它归结为如何应用具有性能的过滤器.

首先是一些明显的事实:

  1. 获取DataAccess/Infrastructure Layer的存储库
  2. 域模型表示业务逻辑并转到域层
  3. 数据访问模型表示持久层,并转到Persistance/Infrastructure/DataAccess层
  4. 业务逻辑转到域层
  5. 规格是业务逻辑,因此它们也属于域层.
  6. 在所有这些示例中,在存储库中使用ORM框架和SQL Server
  7. 持久性模型可能不会泄漏到域层

到目前为止,这么容易.当/如果我们尝试将规范应用于存储库而不破坏DDD模式或存在性能问题时,就会出现问题.

申请规格的可能方式:

1)经典方式:使用域层中的域模型的规范

应用传统的规格模式,使用IsSatisfiedBy方法,返回bool和复合规格以组合多个规格.

这让我们保持域层的规范,但......

  1. 它必须与域模型一起使用,而存储库使用持久性模型来表示持久层的数据结构.这个很容易修复使用映射器,如AutoMapper.
  2. 但是,问题无法解决:所有规格都必须在内存中执行.在大型表/数据库中,如果您必须遍历所有实体仅过滤掉符合您规范的实体,这意味着巨大的影响

2)使用持久性模型的规范

这类似于1),但在规范中使用持久性模型.这允许直接使用规范作为我们的.Where谓词的一部分,它将被转换为查询(即TSQL),并且将在持久性存储(即SQL Server)上执行过滤.

  1. 虽然这会提供良好的性能,但它显然违反了DDD模式.我们的持久性模型泄漏到域层,使得域层依赖于持久层,而不是相反.

3)像2),但使规范成为持久层的一部分

  1. 这不起作用,因为域层需要引用规范.它仍然依赖于持久层.
  2. 我们在持久层内部会有业务逻辑.这也违反了DDD模式

4)像3一样,但使用抽象规范作为接口

我们在Domain层中有规范接口,我们在持久层中的规范的具体实现.现在我们的域层只与接口交互而不依赖于持久层.

  1. 这仍然违反了3)中的#2.我们在持久层中会有业务逻辑,这很糟糕.

5)将表达式树从域模型转换为持久性模型

这当然解决了这个问题,但这是一项非常重要的任务,但它会将规范保留在我们的域层内,同时仍然受益于SQL优化,因为规范成为Repositories Where子句的一部分并转换为TSQL

我试过这种方法,有几个问题(表单实现方面):

  1. 我们需要从Mapper知道配置(如果我们使用它)或保留我们自己的映射系统.这可以部分完成(使用AutoMapper读取Mapper配置),但存在进一步的问题
  2. 对于模型A的一个属性映射到模型B的一个属性的情况是可接受的.如果类型不同(即由于持久性类型,例如枚举被保存为另一个表中的字符串或键/值对,并且我们需要在解析器内进行转换.
  3. 如果多个字段映射到一个目标字段,它会变得非常复杂.我认为这不是域模型 - >持久性模型映射的问题

**6)查询生成器,如API**

最后一个是制作某种查询API,该API被传递到规范中,并且Repository/Persistence层将从中生成表达式树以传递给.Where子句,并使用接口来声明所有可过滤字段.

我也朝这个方向做过几次尝试,但对结果并不太满意.就像是

public interface IQuery<T>
{
    IQuery<T> Where(Expression<Func<T, T>> predicate);
}
public interface IQueryFilter<TFilter>
{
    TFilter And(TFilter other);
    TFilter Or(TFilter other);
    TFilter Not(TFilter other);
}

public interface IQueryField<TSource, IQueryFilter>
{
    IQueryFilter …
Run Code Online (Sandbox Code Playgroud)

domain-driven-design specifications repository repository-pattern

21
推荐指数
3
解决办法
8722
查看次数

域驱动设计和IoC /依赖注入

我现在正在尝试应用我对DDD的了解,我对Domain模型中依赖关系的流程有点困惑.

我的问题是:

  1. 企业是否应该了解域中的工厂,存储库,服务?
  2. 存储库是否应该知道域中的服务?

困扰我的另一件事是当我想要添加集合并将实体添加到集合时如何处理集合.

假设我正在开发一个简单的CMS.在CMS中,我有一个包含标签实体的文章实体和标签集合.

现在,如果我想添加一个新标签的关系.有什么更好的方法呢?(PHP中的示例)

$article->tags->add(TagEntity);
$articleRepository->save($article);
Run Code Online (Sandbox Code Playgroud)

或者我可以用服务来做.

$articleService->addTag($article, TagEntity);
Run Code Online (Sandbox Code Playgroud)

你怎么看?

谢谢.

dependencies domain-driven-design dependency-injection inversion-of-control

13
推荐指数
3
解决办法
8503
查看次数

可以聚合根实体调用存储库

聚合根实体是否可以有一个方法来调用存储库?

我知道不应该,但想得到确认,因为埃里克的书也没有明确说明任何内容:(

还有一件事,我在哪里可以获得领域驱动设计的单元测试示例?

domain-driven-design

6
推荐指数
1
解决办法
3508
查看次数

如何避免贫血数据模型?可以将存储库注入实体吗?

我有一个不可变的User实体:

public class User {
  final LocalDate lastPasswordChangeDate;
  // final id, name, email, etc.
}
Run Code Online (Sandbox Code Playgroud)

我需要添加一个方法,如果必须更改用户的密码,则该方法将返回信息,而不是因为passwordValidIntervalInDays系统设置更改了该密码.

目前的做法:

public class UserPasswordService {
  private SettingsRepository settingsRepository;

  @Inject
  public UserPasswordService(SettingsRepository settingsRepository) {
    this.settingsRepository = settingsRepository;
  }

  public boolean passwordMustBeChanged(User user) {
    return user.lastPasswordChangeDate.plusDays(
        settingsRepository.get().passwordValidIntervalInDays
      ).isBefore(LocalDate.now());
  }
}
Run Code Online (Sandbox Code Playgroud)

问题是如何使上面的代码更加面向对象并避免贫血域模型反模式?是否应该将passwordMustBeChanged方法移动到User如何访问SettingsRepository,是否应该将其注入到User构造函数中,还是应该Settings向ctor提供实例,或者该passwordMustBeChanged方法是否需要提供Settings实例?

代码SettingsSettingsRepository并不重要,但对于完整性,这里是:

public class Settings {
  int passwordValidIntervalInDays;
  public Settings(int passwordValidIntervalInDays) {
    this.passwordValidIntervalInDays …
Run Code Online (Sandbox Code Playgroud)

java oop domain-driven-design

5
推荐指数
1
解决办法
270
查看次数

访问存储库的域实体

继续这些辩论:

DDD - 实体不能直接访问 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

architecture domain-driven-design ddd-repositories repository-pattern

2
推荐指数
1
解决办法
738
查看次数

域对象中的存储库

我看过很多关于这个话题的讨论,但我无法得到令人信服的答案.一般建议不要在域对象中包含存储库.聚合根怎么样?赋予根操纵组合对象的责任是不是正确的?例如,我有一个处理发票的微服务.发票是具有不同产品的聚合根.此服务无需提供有关各个产品的详细信息.我有2个表,一个用于存储发票详细信息,另一个用于存储这些发票的产品.我有两个与表对应的存储库.我在发票域对象中注入了产品存储库.这样做是不对的?

domain-driven-design microservices

2
推荐指数
2
解决办法
542
查看次数