现在,如果涉及复杂的聚合根,我无法获得Spring Data REST背后的概念。如果我正确理解域驱动设计(这是AFAIK弹簧数据的基本原理吗?),那么只能通过存储库公开聚合根。
假设我有两个类Post
和Comment
。两者都是实体,邮政有@OneToMany List<Comment> comments
。
由于Post
显然是聚合根,我想通过PostRepository
访问它。如果我创建@RepositoryRestResource public interface PostRepository extends CrudRepository<Post, Long>
REST访问Post
工作正常。
现在qazxsw poi呈现为内联,并且不像qazxsw poi那样暴露为子资源。只有当我引入comments
时才会发生这种情况(如果我想坚持使用DDD,我不应该这样做)。
那么如何在复杂的域对象中正确使用Spring Data REST?假设你必须检查所有注释都不包含超过X个字符。这显然是由/posts/{post}/comments
聚合根处理的一些不变量。你会把CommentRepository
的逻辑放在哪里?如何将其他类公开为子资源,以便我可以在不引入不必要的存储库的情况下访问Post
?
对于初学者来说,如果对Post.addComment()
有一些约束,那么我会把这个约束放在构造函数调用中。这样,您就不依赖任何外部验证框架或机制来强制执行您的要求。如果您被驱动到基于setter的解决方案(例如通过Jackson),那么您也可以将这些约束放在setter中。
这样,/posts/{post}/comments/{comment}
不必担心强制对Comment
施加约束。
此外,如果您使用Spring Data REST并且仅定义Post
,由于注释的生命周期共同链接到聚合根Comment
,因此流程应为:
PostRepository
及其Post
物品的集合。Post
添加到该集合中。Comment
及其更新的Comment
对象集合放到该资源中。担心碰撞?这就是Post
所使用的标准HTTP标头。如果你在Comment
域对象中添加一个基于conditional operations的属性,那么每次使用新的@Version
更新给定的Post
时,版本都会增加。
获取资源时,Spring Data REST将包含一个E-Tag标头。
这样,您的PUT可以使用HTTP If-Match:<etag>标头进行条件化。如果其他人更新了实体,您将获得412状态代码,表示您应该刷新并重试。
注意:这些条件操作适用于PUT,PATCH和DELETE调用。