Java Spring JPA,更新实体属性时的附加数据库操作

Java Spring JPA,更新实体属性时的附加数据库操作,java,spring,jpa,domain-driven-design,Java,Spring,Jpa,Domain Driven Design,我正在使用SpringJPA设计一个电子商务web应用程序。我有两个类产品和类别,其中产品可以分配到许多类别,但是类别与产品无关 @Entity(name = "products") class Product { @Id @Column(name = "product_id") private Long productId; @ManyToMany @JoinTable( name = "product_category_lin

我正在使用SpringJPA设计一个电子商务web应用程序。我有两个类
产品
类别
,其中
产品
可以分配到许多类别,但是
类别
产品
无关

@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
}
但我认为这是不实际的,因为
产品
仍然可以在其他地方更改类别。例如,在控制器中,用户可以直接从存储库获取
产品
,也可以更改其类别。我不想禁止这个用例

因此,我考虑将逻辑
addCategory(Long productId,Long categoryId)
放入
Product
类本身,这实际上是由域驱动设计建议的。但我不知道该怎么做,因为我无法将
ComplextDBService
注入
产品
。一种方法是将其作为参数传递给
addCategory
方法作为
addCategory(Long productId,Long categoryId,ComplextDBService complexDBService)
,这是一种好的做法吗是否有其他方法将自定义数据库操作逻辑放入域类?

addCategory(长productId、长categoryId、ComplexTDService complexDBService),这是一个好的实践吗

不,不是。在复杂的业务案例中,有时必须将某种“服务”作为参数传递到聚合上调用的方法中,但根据经验,您应该只调用此“服务”上的只读查询方法

是否有其他方法将自定义数据库操作逻辑放入域类中

产品聚合中只应出现与产品相关的事情,例如产品状态的操纵。 您的要求是响应产品集合中的事件

救援领域事件

您需要反转控件。产品聚合应将自身内部的事件通知外部,外部应对此作出反应。产品不应依赖于其他不相关的集合/概念

class Product {
    void addCategory(CategorySnapshot category) {
        categories.add(category);
        eventPublisher.publish(new ProductCategoryAdded(getSnapshot(), category));
    }
}
现在,您应该注册其他组件来侦听ProductCategoryAdded事件,这些其他组件是什么并不重要(如果您需要进行db操作,也许您正在实现CQR?)

您可以自己实现publisher,也可以使用Guava事件总线、Axon等框架

顺便说一下,您缺少DDD的许多重要概念

  • 聚合产品不应该有其他聚合类别的列表(也许您项目的这个有界上下文根本不应该使用DDD实现?
  • 您不应该将对象直接添加到aggregate
    p.getCategories.add(c)
  • //getter、setter
    -它们不是面向对象的
  • addCategory(长productId、长categoryId、ComplexTDService complexDBService),这是一个好的实践吗

    不,不是。在复杂的业务案例中,有时必须将某种“服务”作为参数传递到聚合上调用的方法中,但根据经验,您应该只调用此“服务”上的只读查询方法

    是否有其他方法将自定义数据库操作逻辑放入域类中

    产品聚合中只应出现与产品相关的事情,例如产品状态的操纵。 您的要求是响应产品集合中的事件

    救援领域事件

    您需要反转控件。产品聚合应将自身内部的事件通知外部,外部应对此作出反应。产品不应依赖于其他不相关的集合/概念

    class Product {
        void addCategory(CategorySnapshot category) {
            categories.add(category);
            eventPublisher.publish(new ProductCategoryAdded(getSnapshot(), category));
        }
    }
    
    现在,您应该注册其他组件来侦听ProductCategoryAdded事件,这些其他组件是什么并不重要(如果您需要进行db操作,也许您正在实现CQR?)

    您可以自己实现publisher,也可以使用Guava事件总线、Axon等框架

    顺便说一下,您缺少DDD的许多重要概念

  • 聚合产品不应该有其他聚合类别的列表(也许您项目的这个有界上下文根本不应该使用DDD实现?
  • 您不应该将对象直接添加到aggregate
    p.getCategories.add(c)
  • //getter、setter
    -它们不是面向对象的

  • 不幸的是,DB persistence妨碍了您的DDD模型。当您将产品添加到不同类别时,您需要做什么?不幸的是,DB persistence妨碍了您的DDD模型。当您将产品添加到不同类别时,您需要做什么?