如何解决为什么实体-值关系在 Spring Data JDBC 中实现为反向引用 使用地图让它成为真正的价值
在 Spring Data JDBC 中,如果一个实体(例如 Customer)具有一个值(例如 Address),如示例中的 here,则该值具有反向引用列(表 address 中的列 customer)到数据库架构中的实体:
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
我理解它是如何工作的,但我不理解这个返回参考实现背后的想法。那么有人可以对这个问题有所了解吗?谢谢!
解决方法
至于大多数好问题,答案有很多方面。
历史/对称性答案
当涉及实体之间的引用时,Spring Data 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
称为 值,而我将其称为 实体。如果它应该被视为一个值,我认为你应该将它映射为 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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。