我正在试图弄清楚如何完成以下任务:
User can have many Websites
在向用户添加新网站之前我需要做的是获取网站URL并将其传递给方法,该方法将检查网站是否已存在于数据库中(另一个用户具有相同的网站关联),或是否创建新记录。 < =原因是是创建新缩略图还是使用现有缩略图。
问题是存储库应该是每个聚合根,这意味着我不能做我上面解释的内容? - 我可以首先获取数据库中的所有用户,然后使用if语句查看用户具有相同URL的网站记录的位置,但这将导致无休止且缓慢的过程。
答案 0 :(得分:3)
无论您使用何种存储库方法,您都应该能够以某种方式指定标准。因此,搜索与相关网站相关联的用户 - 如果搜索没有返回用户,则该网站未被使用。
例如,您可以添加具有以下签名的方法(或者将查询对象作为described in this article传递):
User GetUser(string hasUrl);
该方法应该或多或少地生成SQL:
select u.userId
from User u
join Website w
on w.UserId = u.UserId
where w.Url = @url
这应该与直接查询Website
表几乎一样有效;没有必要将所有用户和网站记录加载到内存中。让您的关系数据库完成繁重工作,让您的存储库实现(或对象关系映射器)处理转换。
答案 1 :(得分:1)
我认为您的模型存在根本问题。如果我理解正确,网站是用户聚合组的一部分。这意味着网站实例没有全局范围,仅在属于用户的上下文中才有意义。
但是现在当用户想要添加新网站时,首先要在创建新网站之前检查“网站是否存在于数据库中”。这意味着网站实际上确实具有全球范围。否则,只要用户请求新网站,您就可以为该特定用户创建一个新网站,该网站在该用户范围内具有意义。在这里,您拥有共享的网站,因此在许多用户的范围内具有意义,因此不属于用户聚合。
修复您的模型,您将解决查询困难。
答案 2 :(得分:0)
一种策略是实现可以验证约束的服务。
public interface IWebsiteUniquenessValidator
{
bool IsWebsiteUnique(string websiteUrl);
}
然后你必须实现它,你如何做到这将取决于我不知道的因素,但我建议不要担心通过域。简单一点,它只是一个查询(* - 我会在底部添加这个)。
public class WebsiteUniquenessValidator : IWebsiteUniquenessValidator
{
//.....
}
然后,将“注入”到需要它的方法中。我说“注入”因为我们将从域外提供给域对象,但是..我们将使用方法参数而不是构造函数参数(为了避免要求我们的实体由我们的IoC容器实例化) )。
public class User
{
public void AddWebsite(string websiteUrl, IWebsiteUniquenessValidator uniquenessValidator)
{
if (!uniquenessValidator.IsWebsiteUnique(websiteUrl) {
throw new ValidationException(...);
}
//....
}
}
无论用户及其存储库的用户是什么 - 如果是Service类或CommandHandler - 都可以提供唯一性验证器依赖性。这个消费者应该已经通过IoC接线,因为它将占用UserRepository:
public class UserService
{
private readonly IUserRepository _repo;
private readonly IWebsiteUniquenessValidator _validator;
public UserService(IUserRepository repo, IWebsiteUniquenessValidator validator)
{
_repo = repo;
_validator = validator;
}
public Result AddWebsiteToUser(Guid userId, string websiteUrl)
{
try {
var user = _repo.Get(userId);
user.AddWebsite(websiteUrl, _validator);
}
catch (AggregateNotFoundException ex) {
//....
}
catch (ValidationException ex) {
//....
}
}
}
*我提到简化验证并避开域。
我们构建域来封装修改数据时经常出现的复杂行为。
经验表明,围绕变更数据的要求与查询数据的要求非常不同。
这似乎是您遇到的一个痛点,因为您试图强制读取通过写入系统。
为了减轻这些痛点,可以从写入端分离域中数据的读取。
CQRS是此技术的名称。我只想说,一旦我在CQRS的背景下查看DDD,就会发现一大堆灯泡被点击。我强烈建议您尝试理解CQRS的概念。