2016-10-26 102 views
1

我在我的项目中创建了一个存储库,它将负责用户实体的所有存储操作。我将使用mongo作为客户端的db和mongoreactive。我现在的问题是关于类型。基础架构代码的DDD抽象

trait UserRepository { 
    save(user: User) : ? 
} 

trait MongoUserRepository extends UserRepository { 
    save(user: User) : Future[WriteResult] = { 
     collection.insert(user) 
    } 
} 

在我的域中应该如何建模来自MongoReactive的WriteResult?我不希望它泄漏到我的域名中。有没有现有的模式或好的做法?

回答

1

当我正在执行相同的存储库,我结束了提取WriteResult值我最感兴趣的是在我来说,我结束了以下签名:

trait UserRepository { 
    save(user: User) : Future[Option[String]] 
} 

返回或者一些错误消息或没有什么。因此,实现将如下所示:

trait MongoUserRepository extends UserRepository { 
    save(user: User) : Future[Option[String]] = { 
     collection.insert(user).map(_.errmsg) 
    } 
} 

我结束了这个实现,因为在异常情况下我不会丢失异常消息。

替代方案可能是插入结果映射到Boolean

trait UserRepository { 
    save(user: User) : Future[Boolean] 
} 

trait MongoUserRepository extends UserRepository { 
    save(user: User) : Future[Boolean] = { 
     collection.insert(user).map(_.ok) 
    } 
} 

但在这种情况下,你将失去异常消息。有时它可以很好,但它取决于你的具体情况。

更新:上面贴出的答案适用于0.11版本。在0.12方法errmsg中删除了WriteResult。或者,您可以使用writeErrors,如果Seq不为空,则从全部WriteError中提取所有errmsg

希望它有帮助,先生!

4

在我的域中应该如何建模来自MongoReactive的WriteResult?我不希望它泄漏到我的域名中。有没有现有的模式或好的做法?

通常的做法是域将定义UserRepository特征作为持久性基础结构需要支持的服务提供者接口(spi)。从根本上说,它是表达模型对持久性要求的使用要求的一种方式。

使用的Command Query Separation语言,save命令:那就是改变了仓库的状态的操作。所以这个特性的实现应该符合你的本地编码标准来实现一个命令。

Greg Young的上(generic) repositories

究竟是摆在首位的存储库模式的意图是什么?回顾[DDD,Evans],人们会发现它将代表一系列对象,好像它们是内存中的一个集合,这样就可以解除域的持久性问题。换句话说,目标是将集合语义放在持久化对象上。

所以你也可以到你的收藏库获取灵感。

但一般来说,最常见的选择看起来像

trait UserRepository { 
    save(user: User) : Unit 
} 

所以这是你的具体的实施预计将符合约定。

MongoUserRepository中,您调整了持久性解决方案的实现以满足合同。在这种情况下,这意味着解包Future,检查WriteResult是否有错误,如果写入不成功则抛出异常。

用保存(用户:用户):单位你含蓄把你的客户端的需求来监视库故障(例如:在数据库故障的情况下)

周围其他方式 - 库是一个服务提供商接口;这种设计不会限制客户,而是提供商。在六边形体系结构的术语中,我正在定义secondary port并且约束辅助适配器以符合端口的合同。

动机就是您所描述的动机:存储库消费者应该与需要与选定的持久性解决方案进行交互的协议隔离。领域模型位于业务领域的中间,适配器将业务领域与现实隔离开来。

Evans Chapter 6提出了“防止模型因管理(域对象)生命周期管理复杂性而淹没”的管理挑战。库提供“寻找和获取持久化对象,而封装巨大的基础设施所涉及的手段

库是防火墙

我们正在解决这里的关注点分离;域模型描述您的业务逻辑,我们希望能够清楚地看到商业案例,如果我们必须明确地管理在可变内存集合中发生灾难性修改时发生的情况,这是不可能的。实用的答案是nope out并让应用程序处理它。

That says ..当我写下“符合您当地的编码标准”时,我故意避开了上述情况。如果您的本地指南使用railway oriented programmingmessage driven,那么请务必将其排成一行。域模型绝对没有理由为什么域模型应该关心存储是同步的还是异步的,本地的还是远程的等等。

但是,如果您的域模型开始填充描述实现问题的匹配表达式,我会说你'某处失去了情节。

+1

使用'save(user:User):Unit' *隐式*在您的客户端上要求监视存储库故障(例如:在db故障的情况下),这会迫使以下用法(未指明通过仓库):'try {} catch {case MyFailureException(...)=> ...; _ => ...}'。你不觉得'Try'或'Future'会更好吗? – tkachuko

+0

再给它一个想法,这个确切的方法签名不提供任何从sync(通过此方法签名强制执行)切换到异步API底层库可能具有的简单方法。 – tkachuko