【问题标题】:Why is a entity - value relationship implemented as a back reference in Spring Data JDBC为什么在 Spring Data JDBC 中将实体-值关系实现为反向引用
【发布时间】:2021-09-05 10:40:01
【问题描述】:

在 Spring Data JDBC 中,如果一个实体(例如 Customer)有一个值(例如 Address),如示例 here 中的值有一个反向引用列(表 address 中的列 customer)到 db 架构中的实体:

CREATE TABLE "customer" (
  "id"                  BIGSERIAL       NOT NULL,
  "name"                VARCHAR(255)    NOT NULL,
  PRIMARY KEY (id)
);

CREATE TABLE "address" (
  "customer"            BIGINT,
  "city"                VARCHAR(255)    NOT NULL
);

这样做的问题是,如果您在一个实体或什至在不同实体中多次使用该 Address 值,则必须为每次使用定义一个额外的列。只有实体的主 ID 存储在这些列中,否则无法区分它是哪个实体。在我的实际实现中,Address 值有五个这样的列:

  "order_address"            BIGINT,    -- backreference for orderAddress to customer id
  "service_address"          BIGINT,    -- backreference for serviceAddress to customer id
  "delivery_address"         BIGINT,    -- backreference for deliveryAddress to customer id
  "installation_address"     BIGINT,    -- backreference for installationAddress to provider_change id
  "account_address"          BIGINT,    -- backreference for accountAddress to payment id

我了解它的工作原理,但我不了解这个反向参考实现背后的想法。那么有人可以解释一下这个问题吗?谢谢!

【问题讨论】:

    标签: java spring database-design one-to-one spring-data-jdbc


    【解决方案1】:

    对于大多数好的问题,答案有很多方面。

    历史/对称答案

    当涉及到实体之间的引用时,Spring Data JDBC 支持 1:1(您询问的那个)和 1:N(列表、集合和映射)。 对于后者,除了反向引用之外的任何东西都是奇怪/错误的。 并且使用 1:1 的反向引用变得基本相同,简化了代码,这是一件好事。

    DML 流程答案

    使用反向引用,插入和删除的过程变得更加容易:首先插入聚合根(在您的示例中为customer),然后是所有引用的实体。如果这些实体有更多实体,它会继续工作。删除的工作方式相反,但同样直接。

    依赖答案

    聚合中的引用实体只能作为该聚合的一部分存在。从这个意义上说,它们依赖于聚合根。没有那个聚合根就没有内部实体,而聚合根通常也可以在没有内部实体的情况下存在。因此,内部实体带有引用是有道理的。

    身份证答案

    通过这种设计,内部实体甚至不需要 id。它的身份完全由聚合根的身份给出,如果与同一实体类存在多个一对一关系,则使用反向引用列。

    替代方案

    所有原因或多或少都基于一个一对一的关系。我当然同意,对于同一个班级的两个这样的关系看起来有点奇怪,而在你的例子中是 5,这变得很荒谬。在这种情况下,您可能需要寻找替代方案:

    使用地图

    不要像这样对Customer 类建模:

    class Customer {
      @Id
      Long id;
      String name;
      Address orderAddress
      Address serviceAddress
      Address deliveryAddress
      Address installationAddress
      Address accountAddress
    }
    

    使用这样的地图

    class Customer {
      @Id
      Long id;
      String name;
      Map<String,Address> addresses
    }
    

    这会导致像这样的address

    CREATE TABLE "address" (
      "customer"            BIGINT,
      "customer_key"        VARCHAR(20).    NOT NULL,
      "city"                VARCHAR(255)    NOT NULL
    );
    

    您可以使用@MappedCollection 注释来控制列名,并且您可以根据需要为各个地址添加临时 getter 和 setter。

    让它成为真正的价值

    您将Address 称为,而我将其称为实体。如果应该将其视为一个值,我认为您应该将其映射为 embedded 像这样

    class Customer {
      @Id
      Long id;
      String name;
      @Embedded(onEmpty = USE_NULL, prefix="order_")
      Address orderAddress
      @Embedded(onEmpty = USE_NULL, prefix="service_")
      Address serviceAddress
      @Embedded(onEmpty = USE_NULL, prefix="delivery_")
      Address deliveryAddress
      @Embedded(onEmpty = USE_NULL, prefix="installation_")
      Address installationAddress
      @Embedded(onEmpty = USE_NULL, prefix="account_")
      Address accountAddress
    }
    

    这将使address 表变得多余,因为数据将被折叠到customer 表中:

    CREATE TABLE "customer" (
      "id"                  BIGSERIAL       NOT NULL,
      "name"                VARCHAR(255)    NOT NULL,
      "order_city"          VARCHAR(255)    NOT NULL,
      "service_city"        VARCHAR(255)    NOT NULL,
      "deliver_city"        VARCHAR(255)    NOT NULL,
      "installation_city"   VARCHAR(255)    NOT NULL,
      "account_city"        VARCHAR(255)    NOT NULL,
      PRIMARY KEY (id)
    );
    

    还是聚合?

    但也许您需要自己的地址,而不是作为客户的一部分。 如果是这种情况,地址就是它自己的聚合。 聚合之间的引用应该建模为 id 或 AggregateReference。这在Spring Data JDBC, References, and Aggregates中有更详细的描述

    【讨论】:

    • 感谢您的详细说明 - 有一些背景信息总是很高兴!实际上,我首先使用的是 Map 地址。但是我最终在一个实体中使用了三个 Address 值,而另外两个实体使用了每个 Address 值。我不明白...为什么您认为在我的示例中 AddressDDD 上下文中不是真正的 VALUE,而是一个ENTITY?它没有自己的身份。
    • customer 表中的城市过多。
    • 关于实体与价值。这有点取决于你在哪里看。在数据库中,它确实有一个 id。
    猜你喜欢
    • 2015-05-31
    • 1970-01-01
    • 2021-01-18
    • 2023-03-31
    • 2021-05-22
    • 1970-01-01
    • 2020-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多