我刚刚开始使用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
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)
这是尝试在我的域模型中封装一个简单的规则.我试图捕获的规则是:当出于某种原因,我们更新一个人的出生日期(例如,原始用户输入中存在错误)时,我们需要检查该人的出生地并将其替换为来自其他人的其他值.数据库,如果它在我们的数据库中列为特殊的出生地.
但是,我实现它有两个问题:
此规则修改域实体状态(属性),我需要在用户界面中反映此更改.我的域名模型是POCO.我可以把这个逻辑放在ViewModel中,但这是错误的,因为它不是UI逻辑.这是我需要捕获的一个重要的域规则.
我的SpecialBirthPlaces列表非常大,每次我从数据库中获取客户时我都不想填充它.此外,当规则得到满足时,我需要替换Birthplace.正如我所说,特殊的出生地和替代品的列表非常大,并存储在数据库中.
如何在DDD风格中实现我需要的逻辑?
我一直在努力解决与规范有关的DDD相关问题,我已经阅读了很多关于DDD和规范和存储库的内容.
但是,如果尝试在不破坏域驱动设计的情况下组合所有这三个,则会出现问题.它归结为如何应用具有性能的过滤器.
首先是一些明显的事实:
到目前为止,这么容易.当/如果我们尝试将规范应用于存储库而不破坏DDD模式或存在性能问题时,就会出现问题.
申请规格的可能方式:
1)经典方式:使用域层中的域模型的规范
应用传统的规格模式,使用IsSatisfiedBy方法,返回bool和复合规格以组合多个规格.
这让我们保持域层的规范,但......
AutoMapper.2)使用持久性模型的规范
这类似于1),但在规范中使用持久性模型.这允许直接使用规范作为我们的.Where谓词的一部分,它将被转换为查询(即TSQL),并且将在持久性存储(即SQL Server)上执行过滤.
3)像2),但使规范成为持久层的一部分
4)像3一样,但使用抽象规范作为接口
我们在Domain层中有规范接口,我们在持久层中的规范的具体实现.现在我们的域层只与接口交互而不依赖于持久层.
5)将表达式树从域模型转换为持久性模型
这当然解决了这个问题,但这是一项非常重要的任务,但它会将规范保留在我们的域层内,同时仍然受益于SQL优化,因为规范成为Repositories Where子句的一部分并转换为TSQL
我试过这种方法,有几个问题(表单实现方面):
**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
我现在正在尝试应用我对DDD的了解,我对Domain模型中依赖关系的流程有点困惑.
我的问题是:
困扰我的另一件事是当我想要添加集合并将实体添加到集合时如何处理集合.
假设我正在开发一个简单的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
聚合根实体是否可以有一个方法来调用存储库?
我知道不应该,但想得到确认,因为埃里克的书也没有明确说明任何内容:(
还有一件事,我在哪里可以获得领域驱动设计的单元测试示例?
我有一个不可变的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实例?
代码Settings和SettingsRepository并不重要,但对于完整性,这里是:
public class Settings {
int passwordValidIntervalInDays;
public Settings(int passwordValidIntervalInDays) {
this.passwordValidIntervalInDays …Run Code Online (Sandbox Code Playgroud) 继续这些辩论:
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个表,一个用于存储发票详细信息,另一个用于存储这些发票的产品.我有两个与表对应的存储库.我在发票域对象中注入了产品存储库.这样做是不对的?