如何使用 Spring Data JDBC 建立一对一关系模型?

lol*_*o92 3 java postgresql spring-boot spring-data-jdbc

我想使用 Spring Data JDBC 和 PostgreSQL 建模一对一关系,但我在以正确的方式设置根聚合时遇到问题。

\n\n

有以下场景:图片SQL
\n每个引擎都是唯一的,car具有唯一的列engine_id,该列是 的外键engine.id,同样适用于truck。因此,汽车和卡车应该是根聚合,因此当删除汽车或卡车时,引擎表中引用的行也应该被删除。

\n\n

根据我对Spring Data JDBC 聚合的理解

\n\n
\n

如果多个聚合引用同一实体,则该实体不能成为引用它的聚合的一部分,因为它只能是一个聚合的一部分。

\n
\n\n

所以问题是:

\n\n
    \n
  • 由于上述解释,是否可以采取解决方法,以便通过执行 CRUD 操作cartruck反映更改engine
  • \n
  • 使用 Spring Data JDBC 在 java 中实现这种关系的最佳方法是什么?
  • \n
\n\n

这是我的看法,虽然行不通,但应该澄清我想要完成的任务。

\n\n

汽车.java

\n\n
package com.example.dao.model;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.domain.Persistable;\nimport org.springframework.data.relational.core.mapping.Column;\nimport org.springframework.data.relational.core.mapping.Table;\n\nimport java.util.UUID;\n\n@Table("car")\npublic class Car implements Persistable<UUID> {\n\n    @Id\n    private UUID id;\n\n    String brand;\n\n    String model;\n\n    @Column("engine_id")\n    Engine engine;\n\n    public void setId(UUID id) {\n        this.id = id;\n    }\n\n    @Override\n    public UUID getId() {\n        return id;\n    }\n\n    @Override\n    public boolean isNew() {\n        return id == null;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

引擎.java

\n\n
package com.example.dao.model;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.domain.Persistable;\nimport org.springframework.data.relational.core.mapping.Table;\n\nimport java.time.LocalDateTime;\nimport java.util.UUID;\n\n@Table("engine")\npublic class Engine implements Persistable<UUID> {\n\n    @Id\n    private UUID id;\n\n    String name;\n\n    LocalDateTime dateCreated;\n\n    String type;\n\n    public void setId(UUID id) {\n        this.id = id;\n    }\n\n    @Override\n    public UUID getId() {\n        return id;\n    }\n\n    @Override\n    public boolean isNew() {\n        return id == null;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

卡车.java

\n\n
package com.example.dao.model;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.domain.Persistable;\nimport org.springframework.data.relational.core.mapping.Column;\nimport org.springframework.data.relational.core.mapping.Table;\n\nimport java.util.UUID;\n\n@Table("truck")\npublic class Truck implements Persistable<UUID> {\n\n    @Id\n    private UUID id;\n\n    String brand;\n\n    String model;\n\n    Integer cargoMaxWeight;\n\n    String truckType;\n\n    @Column("engine_id")\n    Engine engine;\n\n    public void setId(UUID id) {\n        this.id = id;\n    }\n\n    @Override\n    public UUID getId() {\n        return id;\n    }\n\n    @Override\n    public boolean isNew() {\n        return id == null;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Jen*_*der 6

我看到有四个选项可以用 Java 对此进行建模。请注意,其中大多数都需要调整您的数据库架构。

一般问题是 Spring Data JDBC 假定引用的实体 ( Engine) 在其表中有一列引用所属实体 ( Car/ Vehicle)。这有一个问题: https: //jira.spring.io/browse/DATAJDBC-128 从这里开始,您有以下选项:

  1. 添加到引擎表的列,产生如下所示的实体和模式(所有实体都减少到与问题相关的最小程度):

    public class Car {
    
        @Id
        Long id;
        String name;
    
        Engine engine;
    }
    
    public class Truck {
    
        @Id
        Long id;
        String name;
    
        Engine engine;
    }
    
    public class Engine {
    
        String name;
    }
    
    CREATE TABLE CAR (
      id   BIGINT IDENTITY,
      NAME VARCHAR(200)
    );
    
    CREATE TABLE TRUCK (
      ID   BIGINT IDENTITY,
      NAME VARCHAR(200)
    );
    
    CREATE TABLE ENGINE (
      TRUCK BIGINT,
      CAR   BIGINT,
      NAME  VARCHAR(200),
      FOREIGN KEY (TRUCK) REFERENCES TRUCK (ID),
      FOREIGN KEY (CAR) REFERENCES CAR (ID)
    );
    
    Run Code Online (Sandbox Code Playgroud)

    我在 GitHub 上提供了一个完整的示例: https: //github.com/schauder/so-sd-jdbc-multipleonetoone

  2. 如果您不喜欢这两列,您可以修改映射以对两个引用使用同一列。但是你必须确保 和 的 idCarVehicle不同的。即使这样,这种方法也存在一个大问题:

    deleteAllCar存储库或Truck车辆上将删除所有引擎! 所以不推荐这种方法!

    如果您仍然想使用它,这里是模式和实体的代码。

    public class Car {
    
        @Id
        Long id;
        String name;
    
        @Column(value = "vehicle")
        Engine engine;
    }
    
    public class Truck {
    
        @Id
        Long id;
        String name;
    
        @Column(value = "vehicle")
        Engine engine;
    }
    
    public class Engine {
    
        String name;
    }
    
    
    CREATE TABLE CAR (
      id   BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY ,
      NAME VARCHAR(200)
    );
    
    CREATE TABLE TRUCK (
      ID   BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH -1, INCREMENT BY -1) PRIMARY KEY ,
      NAME VARCHAR(200)
    );
    
    CREATE TABLE ENGINE (
      VEHICLE   BIGINT,
      NAME  VARCHAR(200),
    );
    
    Run Code Online (Sandbox Code Playgroud)

    完整的示例在此提交中:https://github.com/schauder/so-sd-jdbc-multipleonetoone/tree/5570979ef85e30fe7a17a8ce48d867fdb79e212a

  3. 有两个单独的Engine类和表。一个用于Cars,一个用于Trucks。

  4. 如果您不想或无法更改数据库架构,您可以考虑EngineCarTruck三个单独的聚合。你会有一个Long engineIdinCar和 in Truck然后可以使用的事件侦听器来AfterDeleteEvent完成级联删除。