我试图了解如何正确使用存储库模式.Aggregate Root的核心概念不断涌现.在搜索Web和Stack Overflow以获取有关聚合根的帮助时,我会不断发现有关它们的讨论以及指向应该包含基本定义的页面的死链接.
在存储库模式的上下文中,什么是聚合根?
design-patterns ddd-repositories aggregateroot repository-pattern
我已经在我的项目中使用Spring Data JPA存储库一段时间了,我知道以下几点:
findByCustomerNameAndPhone()(假设customerName和phone是域对象中的字段).我感兴趣的是如何对它进行编码,我已经查看了Spring JPA源代码和API,但我找不到以下问题的答案:
您能否帮助解决上述问题并提供任何支持的文档?
我有一个具有编辑器和项目概念的域模型.
编辑拥有许多项目,项目不仅有编辑所有者,还有许多编辑成员.因此,编辑还有一些"加入"项目.
我正在采用DDD方法对此进行建模并使用Repository模式进行持久化.但是,我还没有足够好地确定模式,以确定我应该如何做到这一点.
我正在假设编辑器和项目可能在同一个聚合中,其中根是编辑器.因此,我可以获得一个编辑器,然后枚举其项目,并可以从那里枚举项目的成员编辑.
但是,如果我只被允许从我的存储库中检索编辑器,这是不是意味着当我获得拥有它们的编辑器时我必须从存储库加载所有项目?如果我想延迟加载成员编辑器,项目还需要对存储库的引用?
或者,如果我拆分聚合并拥有一个编辑器存储库和一个项目存储库,那么我应该如何处理两者之间的事务,例如将新项目添加到编辑器中?例如:
Editor e = new Editor("Editor Name");
editorRepository.Add(e);
Project p = e.CreateProject("Project Name");
projectRepository.Add(p); // These two lines
editorRepository.Save(e); // should be atomic
Run Code Online (Sandbox Code Playgroud)
我是否误解了Repository模式的意图?
domain-driven-design aggregate lazy-loading ddd-repositories repository-pattern
根据Fowler(此处),存储库"在域和数据映射层之间进行调解,就像内存域对象集合一样." 因此,例如,在我的Courier Service应用程序中,当提交新的运行时,我的应用程序服务会创建一个新的运行聚合根对象,使用请求中的值填充它,然后将其添加到RunRepository,然后再调用要保存的工作单元对数据库的更改.当用户想要查看当前运行的列表时,我查询相同的存储库并返回表示该信息的非规范化DTO.
但是,在查看CQRS时,查询不会访问同一个存储库.相反,它可能直接针对数据存储并始终是非规范化的.我的命令方将演变为NewRunCommand和Handler,它将创建并填充NewRun域对象,然后将信息保存到数据存储.
所以第一个问题是,如果我们不维护域对象的内存中集合(缓存,如果你愿意的话),那么存储库在哪里适用于CQRS模型?
考虑提交给我的应用程序服务的信息只包含服务必须解析以构建域对象的一系列ID值的情况.例如,请求包含分配给运行的信使的ID#.服务必须根据ID值查找实际的Courier对象,并使用AssignCourier方法(验证信使并执行其他业务逻辑)将对象分配给NewRun.
另一个问题是,鉴于查询分离和可能缺少存储库,应用程序服务如何执行查找以查找Courier域对象?
UPDATE
根据丹尼斯评论后的一些额外阅读和思考,我将重新解释我的问题.
在我看来,CQRS鼓励仅仅是数据访问和数据存储机制的外观的存储库.它们给出了一个集合的"外观"(如Fowler描述的那样),但并没有在内存中管理实体(正如Dennis指出的那样).这意味着存储库上的每个操作都是直通的,是吗?
工作单位如何适应这种方法?通常,UoW用于提交对存储库所做的更改(对吗?),但如果存储库没有将实体维护在内存中,那么UoW有什么作用?
关于"写入"操作,命令处理程序是否会引用相同的存储库,不同的存储库或者可能是UoW而不是存储库?
我刚刚开始使用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
我有关于DDD和存储库模式的问题.
假设我有Customer聚合根的Customer存储库.Get&Find方法返回完全填充的聚合,其中包括Address等对象.一切都很好.但是当用户在UI中搜索客户时,我只需要聚合的"摘要" - 只是一个包含汇总信息的扁平对象.
我可以处理的一种方法是正常调用存储库中的find方法,然后在应用程序层中将每个客户聚合映射到CustomerSearchResult/CustomerInfo DTO,并将它们发送回客户端.
但我的问题是性能; 每个Customer聚合可能需要多个查询来填充所有关联.因此,如果我的搜索条件与50个客户相匹配,那么在数据库中可能会检索到我甚至不需要的数据.
另一个问题是,我可能希望在客户的聚合根边界之外包含有关客户的汇总数据,例如最后一个订单的日期.订单有自己的聚合,因此要获取客户的订单信息,我必须调用OrderRepository,这也会降低性能.
所以现在我觉得我有两种选择:
向CustomerRepository添加一个额外的Find方法,该方法通过执行一个有效的查询来返回这些摘要对象的列表.
创建一个专门构建的只读CustomerInfoRepository,它只有1中描述的find方法.
但这两种感觉都让我觉得我违背了DDD的原则.我的存储库继承自通用基础:存储库,其中T:IAggregateRoot.这些摘要信息对象不是聚合,并且与T的类型不同,所以#1真的违背了设计.
也许对于#2,我会创建一个没有IAggregateRoot约束的抽象SearchRepository?
我的域中有许多类似的场景.
你会如何实现这种情况?
谢谢,戴夫
更新
在阅读Theo的答案之后,我想我会选择#2选项并在我的基础架构中创建一个专门的SearchRepository,以适应这些场景.然后,应用程序层(WCF服务)可以调用这些直接填充摘要DTO的存储库,而不是将域实体映射到DTO.
****更新2****
虽然我在一年多前问过这个问题,但我想我只是补充说我已经发现了CQRS,它旨在解决这个问题.Udi Dahan(http://www.udidahan.com/)和Greg Young(http://codebetter.com/gregyoung/)已经写了很多关于它的文章.如果您使用DDD创建分布式应用程序,CQRS适合您!
.net c# domain-driven-design ddd-repositories repository-pattern
DDD指定每个聚合的存储库,但是当采用Spring Data JPA时,我们只有在声明每个实体的接口时才能利用这些优势.如何解决阻抗不匹配问题?
我希望尝试封装在聚合存储库中的存储库接口,这是一个好的解决方案还是更好的可用解决方案?
到给定的一个例子:Customer是聚合根和实体等Demographics,Identification,AssetSummary等等,其中每个实体可以从具有自己的资源库接口受益.没有违反DDD的最佳方法是什么?
domain-driven-design ddd-repositories spring-data spring-data-jpa
我对领域驱动设计方法感到困惑.从网上的消息来源我明白这是隔离你的方式Domain Objects,Database Objects但我不明白两者之间的区别.
举个例子,我们来看看django教程中的民意调查代码,有两个模型Polls和Choice.
这些domain level objects还是database level objects?
是否需要带有ORM的DDD?
如果是,您是否可以提供需要将DDD方法与ORM一起使用的良好情况
例如,这是模型
class Polls(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
Run Code Online (Sandbox Code Playgroud)
DDD方法代码我见过人们写作
class PollService(object):
def __init__(self, poll_repository):
self.poll_respository = poll_respository
def update(self, poll_id):
poll = self.poll_respository.fetch_by_id(poll_id)
poll.question += '?'
self.poll_respository.update(poll)
#assume that the following code works?
class PollRepository():
def __init__(self, db):
self.db = db
def update(self, poll):
try:
self.db.session().add(poll)
self.db.session.commit()
except Exception:
self.db.session.rollback()
Run Code Online (Sandbox Code Playgroud)
这是正确的方法吗?我在这里看到了很多冗余代码,但人们说这Polls是一个域级对象,它不应该直接与数据库对话? …
背景
我正在尝试创建一个简单的应用程序来真正理解整个DDD + TDD +等堆栈.我的目标是在运行时动态注入DAL存储库类.这使我的域和应用程序服务层可以测试.我计划使用"穷人的DI"来实现这一目标...所以我会在启动附近的一个简单的控制台应用程序中执行此操作:
// Poor man's DI, injecting DAL repository classes at runtime
var productRepository = new SimpleOrder.Repository.ProductRespository();
var customerRepository = new SimpleOrder.Repository.CustomerRepository();
var orderRepository = new SimpleOrder.Repository.OrderRepository();
// Constructor injection into this class in the Application Services layer,
// SimpleOrder.ApplicationFacade
OrderEntry oe = new OrderEntry(customerRepository, orderRepository, productRepository);
为了实现这种依赖注入,我创建了三个存储库接口:
-- ICustomerRepository -- IOrderRepository -- IProductRespository
一个典型的实现:
namespace SimpleOrder.Domain.Interfaces
{
public interface ICustomerRepository
{
Customer GetCustomerById(int customerId);
void SaveCustomer(Customer customer);
}
}
**请注意,SaveCustomer引用了域层中定义的Customer模型类.这是其他存储库的典型.
但是我不确定应该在哪个项目/层实施.我在解决方案中有5个项目:
SimpleOrder.ConsoleClient(presentation) - 我想从这里注入域的特定实现作为应用程序
SimpleOrder.ApplicationFacade(应用程序服务) - …
domain-driven-design interface ddd-repositories layer n-tier-architecture
在我的应用程序中有几层.本主题将重点介绍域和基础结构层.
我在域层中有存储库接口ClientRepositoryInterface.我在Infrastructure层中实现了此接口ClientRepositoryImpl.
但是为了在其存在的循环中间重建对象,我需要工厂(ReconstitutionClientFactory).调用工厂将在存储库中.埃里克埃文斯的书被描述为正常的做法.
但是应该找到这个工厂(ReconstitutionClientFactory)?在域或基础架构层?
我想在Domain ...但是!但是下层会直接调用更高层!这是错的,但怎么做对了?
domain-driven-design ddd-repositories repository-pattern factory-pattern
ddd-repositories ×10
spring-data ×2
.net ×1
aggregate ×1
c# ×1
cqrs ×1
django ×1
interface ×1
java ×1
layer ×1
lazy-loading ×1
python ×1
spring ×1