在Spring中,如果一个实体(例如,Customer)有一个值(例如地址),如示例这里中的值,则该值有一个返回引用列(表地址中的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
);这方面的问题是,如果您在一个实体中或甚至在不同的实体中多次使用该地址值,则必须为每次使用定义一个额外的列。只有实体的主要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我理解它是如何工作的,但我不理解这个反向引用实现背后的想法。那么,谁能在这个问题上说点什么呢?谢谢!
发布于 2021-06-22 06:25:42
对于大多数好的问题,答案有很多方面。
历史/对称答案
当涉及实体之间的引用时,Spring数据JDBC支持1:1 (您询问的对象)和1:N (列表、集和映射)。对于后者,除了反向引用以外的任何东西都是奇怪的/错误的。使用1:1的反向引用基本相同,简化代码,这是一件好事。
DML过程答案
使用反向引用,插入和删除的过程变得容易得多:首先插入聚合根(在示例中是customer),然后是所有引用的实体。如果这些实体有更多的实体,它将继续发挥作用。删除的工作方式相反,但同样是直接前进。
依赖答案
聚合中的引用实体只能作为该聚合的一部分存在。从这个意义上讲,它们依赖于聚合根。如果没有聚合根,就没有内部实体,而聚合根通常也是没有内部实体而存在的。因此,内部实体携带引用是有意义的。
ID回答
使用此设计,内部实体甚至不需要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称为值,而我将其称为实体。如果它应该被认为是一个值,我认为您应该将它映射为一个嵌入式,如下所示
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)
);或者它是一个集合?
但也许你需要的是他们自己的地址,而不是作为客户的一部分。如果是这样的话,地址就是它自己的聚合。聚合之间的引用应该被建模为ids或AggregateReference。这在https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates中有更详细的描述。
https://stackoverflow.com/questions/68073332
复制相似问题