首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在Spring数据JDBC中将实体值关系作为反向引用实现?

为什么在Spring数据JDBC中将实体值关系作为反向引用实现?
EN

Stack Overflow用户
提问于 2021-06-21 18:59:03
回答 1查看 293关注 0票数 1

在Spring中,如果一个实体(例如,Customer)有一个值(例如地址),如示例这里中的值,则该值有一个返回引用列(表地址中的customer列)到db模式中的实体:

代码语言:javascript
复制
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
);

这方面的问题是,如果您在一个实体中或甚至在不同的实体中多次使用该地址值,则必须为每次使用定义一个额外的列。只有实体的主要id存储在这些列中,否则无法区分它是哪一个实体。在我的实际实现中,我有以下五个列作为Address值:

代码语言:javascript
复制
  "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

我理解它是如何工作的,但我不理解这个反向引用实现背后的想法。那么,谁能在这个问题上说点什么呢?谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-06-22 06:25:42

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

历史/对称答案

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

DML过程答案

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

依赖答案

聚合中的引用实体只能作为该聚合的一部分存在。从这个意义上讲,它们依赖于聚合根。如果没有聚合根,就没有内部实体,而聚合根通常也是没有内部实体而存在的。因此,内部实体携带引用是有意义的。

ID回答

使用此设计,内部实体甚至不需要id。它的标识是由聚合根的标识完美地给出的,如果同一个实体类存在多个一对一的关系,则使用反向引用列。

备选方案

所有的原因或多或少都是基于一对一的关系。我当然同意,对于同一个类来说,两个这样的关系看起来有点奇怪,对于5,就像在您的例子中一样,它变得可笑了。在这种情况下,您可能需要考虑其他方法:

用地图

而不是像这样建模您的Customer类:

代码语言:javascript
复制
class Customer {
  @Id
  Long id;
  String name;
  Address orderAddress
  Address serviceAddress
  Address deliveryAddress
  Address installationAddress
  Address accountAddress
}

用这样的地图

代码语言:javascript
复制
class Customer {
  @Id
  Long id;
  String name;
  Map<String,Address> addresses
}

,这将导致如下所示的address

代码语言:javascript
复制
CREATE TABLE "address" (
  "customer"            BIGINT,
  "customer_key"        VARCHAR(20).    NOT NULL,
  "city"                VARCHAR(255)    NOT NULL
);

您可以使用@MappedCollection注释来控制列名,如果需要,还可以为单个地址添加临时getter和setter。

让它成为一个真正的价值

您将Address称为值,而我将其称为实体。如果它应该被认为是一个值,我认为您应该将它映射为一个嵌入式,如下所示

代码语言:javascript
复制
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表中:

代码语言:javascript
复制
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)
);

或者它是一个集合?

但也许你需要的是他们自己的地址,而不是作为客户的一部分。如果是这样的话,地址就是它自己的聚合。聚合之间的引用应该被建模为ids或AggregateReference。这在https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates中有更详细的描述。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68073332

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档