postgresql - Hibernate - Spring Boot - 将具有外键的对象保存到另一个表
问题描述
我使用 Hibernate 和 Spring Boot,但遇到以下问题:我想在 PostgreSQL 中保存我的 Framework 类型的对象:
public class Framework extends BaseEntity {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "sorting_type_id", unique = true)
private FrameworkSortingType frameworkSortingType;
我的FrameworkSortingType
实体:
@Entity(name = "framework_sorting_type")
@Data
@NoArgsConstructor
public class FrameworkSortingType extends BaseEntity {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "environmental_id", referencedColumnName = "id")
private SortingType environmental;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "social_id", referencedColumnName = "id")
private SortingType social;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "governance_id", referencedColumnName = "id")
private SortingType governance;
}
和SortingType
实体:
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "sorting_type")
public class SortingType extends BaseEntity {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "type")
private String type;
}
我正在做以下测试 -Postman
我想保存这样一个对象(没有 ID 的 frameworkSortingType 对象):
{
"id": 335799,
"frameworkSortingType": {
"environmental":{
"type": "alphabetically"
},
"social":{
"type": "numerically"
},
"governance":{
"type": "alphabetically"
}
}
}
我的 SortingType 表只有 2 个常量行:
id type
1 alphabetically
2 numerically
而且我只想在我的表中存储FrameworkSortingType
表的外键 ID,SortingType
但目前存储在我FrameworkSortingType
全新的 ID 中的SortingType
表中,其中添加了具有新值的新行(并且SortingType
表不应该被修改,因为应该像一个 ENUM 但 -> 已通过添加新行进行更改):
SortingType表:
并且在我的FrameworkSortingType
表中保存了全新的 ID,SortingType
而不是像 1 或 2 这样的外键 ID(而不是 751801 应该是 1 作为 PK in SortingType
,而不是 751803 应该是 2 作为 PK fromSortingType
等):
问题出在哪里?我在哪里犯错了?也许我应该更改从前端发送的数据?当然,我想发送到后端值,如“按字母顺序”而不是 ID,因为每个数据库的 ID 可能不同。
编辑
当我从 FrameworkSortingType 实体中删除 cascade=CascadeType.ALL 时,一切都按预期工作,但我宁愿只从前端发送值而没有 SortingType 表的 ID(在我的情况下,它就像 DB 中的枚举)
解决方案
您应该避免从任何类型的交互中更新主(也称为主要参考)表,您只能离线或通过某些管理界面更新它。此外,无论您在何处使用 JoinColumn
该实体,复习都会成为该实体的拥有方。因此,在这种情况下,来自该实体的任何操作都将适用于 OneToOne 等关联注释。所以请谨慎使用 Cascade.ALL。
以下是我对实体所做的一些更改以及我是如何实现的。
@Entity
@Table(name = "sorting_type")
public class SortingType {
@Id
@GeneratedValue
@Type(type = "uuid-char")
private UUID id;
@Enumerated(value = EnumType.STRING)
private SortingTypeName name;
public enum SortingTypeName {
ALPHABETICAL,
NUMERICALLY
}
public UUID getId() {
return id;
}
public SortingTypeName getName() {
return name;
}
public void setName(SortingTypeName name) {
this.name = name;
}
public static SortingType newAlphabetSortingType() {
SortingType sortingType = new SortingType();
sortingType.name = SortingTypeName.ALPHABETICAL;
return sortingType;
}
public static SortingType newNumericSortingType() {
SortingType sortingType = new SortingType();
sortingType.name = SortingTypeName.NUMERICALLY;
return sortingType;
}
}
@Entity
@Table(name = "framework_sorting_type")
public class FrameworkSortingType {
@Id
@GeneratedValue
@Type(type = "uuid-char")
private UUID id;
@OneToOne
@JoinColumn(name = "environmental_id")
private SortingType environmental;
@OneToOne
@JoinColumn(name = "social_id")
private SortingType social;
@OneToOne
@JoinColumn(name = "governance_id")
private SortingType governance;
public UUID getId() {
return id;
}
public SortingType getEnvironmental() {
return environmental;
}
public void setEnvironmental(SortingType environmental) {
this.environmental = environmental;
}
public SortingType getSocial() {
return social;
}
public void setSocial(SortingType social) {
this.social = social;
}
public SortingType getGovernance() {
return governance;
}
public void setGovernance(SortingType governance) {
this.governance = governance;
}
}
@Entity
@Table(name = "framework")
public class Framework {
@Id
@GeneratedValue
@Type(type = "uuid-char")
private UUID id;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "framework_id")
private FrameworkSortingType frameworkSortingType;
public UUID getId() {
return id;
}
public FrameworkSortingType getFrameworkSortingType() {
return frameworkSortingType;
}
public void setFrameworkSortingType(FrameworkSortingType frameworkSortingType) {
this.frameworkSortingType = frameworkSortingType;
}
}
单元测试来证明这个概念
@ExtendWith(SpringExtension.class)
@Transactional
@SpringBootTest(classes = TestApplication.class)
class MasterTableExample {
@Autowired
private EntityManager entityManager;
@Rollback(false)
@Test
void testSortingTypeSave() {
SortingType alphabetType = SortingType.newAlphabetSortingType();
SortingType numericType = SortingType.newNumericSortingType();
entityManager.persist(alphabetType);
entityManager.persist(numericType);
Assertions.assertNotNull(alphabetType.getId());
Assertions.assertNotNull(numericType.getId());
// Prepare FrameworkSortingType object
FrameworkSortingType frameworkSortingType = new FrameworkSortingType();
frameworkSortingType.setEnvironmental(searchSortingType(SortingType.SortingTypeName.ALPHABETICAL));
frameworkSortingType.setSocial(searchSortingType(SortingType.SortingTypeName.NUMERICALLY));
frameworkSortingType.setGovernance(searchSortingType(SortingType.SortingTypeName.NUMERICALLY));
// Prepare Framework object
Framework framework = new Framework();
framework.setFrameworkSortingType(frameworkSortingType);
entityManager.persist(framework);
Assertions.assertNotNull(frameworkSortingType.getId());
Assertions.assertNotNull(framework.getId());
}
private SortingType searchSortingType(SortingType.SortingTypeName name) {
return (SortingType) entityManager.createQuery("select st from SortingType st where st.name='" + name + "'").getSingleResult();
}
}
我使用Rollback(false)
了以防万一您希望在测试执行后查看 db 中仍然存在的更改。
我们之前存储了 Enum 实体。当使用 FrameworkStoringType 创建框架时,无论SoringType
表是否更新,数据都会持久保存。尝试添加entityManager.remove(framework);
您将看到的语句的结尾framework
以及frameworkstoringtype
从数据库中删除的语句,并且 SortingType 持久行没有任何反应。你可以看到我没有使用entity.persist(frameworkSortingType)
协会为我做的。
请注意,我已从中删除cascade = CascadeType.ALL
,FrameworkSortingType
因为这可能会导致从SortingType
表中额外添加和删除。
推荐阅读
- microsoft-dynamics - 用于将更改发布到 ServiceBus 的 Common Data Services Logic App Connector 或服务端点
- c# - OpenGL4 - 如何旋转对象以查看另一个对象
- git - Github SSH 密钥被忽略
- typescript - 为什么打字稿将任何分配给明确定义的类型?
- python - 用换行符分隔 python 元组
- docker - 在 Docker 容器中构建 .NET Core 项目时,如何将 GitVersion 集成到 TeamCity 中?
- php - 来自 Web 服务的 PHP 字符串比较
- python - 每次使用 python 启动系统时制作本地键盘记录器发送电子邮件
- date - Flutter/Dart - 在输入表单中格式化日期
- java - Java中根据年龄和性别随机生成团队