我正在使用Spring JPA设计电子商务Web应用程序。我有两个类Product
和Category
,其中Product
可以分配到许多类别,但Category
不关心Product
。
@Entity(name = "products")
class Product {
@Id
@Column(name = "product_id")
private Long productId;
@ManyToMany
@JoinTable(
name = "product_category_links",
joinColumns = @JoinColumn(name = "product_id", referencedColumnName = "product_id"),
inverseJoinColumns = @JoinColumn(name = "category_id", referencedColumnName = "category_id"))
private List<Category> categories;
// getters, setters,
}
@Entity(name = "categories")
class Category {
@Id
@Column(name = "category_id")
private Long category_id;
// getters, setters
}
当Product
的类别发生变化时,我还需要更新数据库中的内容。我正在考虑通过创建专用服务方法来更新产品类别来保持这种完整性。
class ProductService
@Autowired
private ProductRepository productRepository;
private ComplexDBService complexDBService;
@Transactional
public void addCategory(Long productId, Long categoryId) {
Product p = productRepository.findByProductId(productId);
Category c = categoryRepository.findByCategoryId(categoryId);
p.getCategories.add(c);
complexDBService.doSomething();
}
}
但我认为这是不实际的,因为Product
仍然可以在其他地方改变类别。例如,在控制器中,有人可以直接从存储库获取Product
可以更改其类别。我不想禁止这个用例。
所以我想把逻辑addCategory(Long productId, Long categoryId)
放在Product
类中,这实际上是由Domain Driven Design提出的。但我无法弄清楚如何做到这一点,因为我无法将ComplextDBService
注入Product
。一种方法是将它作为addCategory
方法的参数传递为addCategory(Long productId, Long categoryId, ComplextDBService complexDBService)
,这是一个好习惯吗?是否有其他方法将自定义数据库操作逻辑放在域类中?
addCategory(Long productId,Long categoryId,ComplextDBService complexDBService),这是一个很好的做法吗?
不,不是。在复杂的业务案例中,您有时必须将某种“服务”作为参数传递给在聚合上调用的方法,但根据经验,您应该只在此“服务”上调用只读查询方法。
是否有其他方法将自定义数据库操作逻辑放在域类中?
应该只在产品聚合中发生与产品相关的事情,例如操纵产品状态。您的要求是响应Product aggregate内的事件。
域事件救援
您需要反转控件。产品总量应告知外部有关其内部的事件,外部应对此作出反应。产品不应该依赖于其他不相关的聚合/概念。
class Product {
void addCategory(CategorySnapshot category) {
categories.add(category);
eventPublisher.publish(new ProductCategoryAdded(getSnapshot(), category));
}
}
现在你应该注册其他组件来监听ProductCategoryAdded事件,那些其他组件是什么并不重要(如果你需要进行数据库操作,也许你正在实现CQRS?)。
您可以自己实现发布者或使用Guava Event Bus,Axon等框架。
顺便说一句,你缺少许多重要的DDD概念。
p.getCategories.add(c)
所拥有的列表中//getters, setters
- 那些不是面向对象的......