java - 调用 @Repository.save() 后,延迟加载的 @ManyToOne 列被覆盖为 null
问题描述
在我的 Spring Boot 项目中,我有以下与父@ManyToOne
级相同的关系字段。@Entity
@Entity
@Table(name="workspace")
public class Workspace extends AbstractEntity {
@NaturalId
@Column(nullable=false, unique=true)
private String code;
@ManyToOne(fetch=FetchType.LAZY, optional=true)
@LazyToOne(LazyToOneOption.NO_PROXY)
@JoinColumn(name="default_workspace", referencedColumnName="code")
private Workspace parent;
private String name;
private String shortName;
}
延迟加载行为按预期工作。但是,每次我调用@Repository.save()
它时@Entity
,该default_workspace
字段都会设置为NULL
。
更新:包括评论中要求的一些配置
为了使用 Hibernate 启用延迟加载,我简单地将hibernate-enhance-maven-plugin
插件包含在我的pom.xml
.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ft</groupId>
<artifactId>com.ft.admin</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.ft</groupId>
<artifactId>com.ft.common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.hibernate.orm.tooling</groupId>
<artifactId>hibernate-enhance-maven-plugin</artifactId>
<version>${hibernate.version}</version>
<executions>
<execution>
<configuration>
<failOnError>true</failOnError>
<enableLazyInitialization>true</enableLazyInitialization>
</configuration>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
要在 my 上执行 CRUD 程序Workspace
,我使用以下@Repository
.
@Repository
public interface WorkspaceRepo extends CrudRepository<Workspace, Integer> {
Optional<Workspace> findByCode(String workspaceCode);
}
默认情况下,在 Spring Boot 中,事务的边界保持在对@Repository
. 因此,为了能够访问我的延迟加载字段而不会遇到LazyInitializationException: no Session
,我添加@Transactional
到我@Service
的以扩展事务边界,如下所示。
@Service
@Transactional
public class AppAdminService {
@Autowired
private WorkspaceRepo workspaceRepo;
public void updatePsyWorkspace() {
Workspace childWorkspace = workspaceRepo.findByCode("PSY").get();
childWorkspace.setShortName("PSY SHORT");
workspaceRepo.save(childWorkspace);
}
}
当我执行时WorkspaceRepo.findByCode(code)
,我会返回一个具有有效非 null 的子记录parent
。但是,每当我执行时WorkspaceRepo.save(childWorkspace)
,即使我只更新了上面示例中所示的字段,也会将其parent
设置为NULL
并且该default_workspace
列也会进入数据库。NULL
ShortName
更新:临时解决方案
作为临时解决方案,我必须String
为该default_workspace
列包含一个普通字段,并从 Hibernate 操作中排除该parent
字段,如下所示。
@Entity
@Table(name="workspace")
@Getter @Setter
public class Workspace extends AbstractEntity {
...
@ManyToOne(fetch=FetchType.LAZY, optional=true)
@LazyToOne(LazyToOneOption.NO_PROXY)
@JoinColumn(
name="default_workspace",
referencedColumnName="code",
insertable=false,
updatable=false)
private Workspace parent;
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
@Column(name="default_workspace")
private String defaultWorkspace;
public void setParent(Workspace parent) {
this.parent = parent;
this.defaultWorkspace = (parent != null) ? parent.getCode() : null;
}
...
}
通过使用AccessLevel.NONE
,我将这个字段完全隐藏在外界面前。任何更新字段的调用parent
都会额外更新该defaultWorkspace
字段。尽管这个解决方案有效,但我觉得它不合适。
如果您能向我展示实现相同目标的更好方法,我将不胜感激。
解决方案
推荐阅读
- r - 官员包是否接受 ggsurvplot-object?
- sqlalchemy - 双方都有外键的 OneToOne 关系
- javascript - 将表格行数据传递给点击功能
- c# - 如何以编程方式更改默认 MS-Word 字体
- javascript - 使用 Javascript (OTRS) 打开下拉菜单选项
- python - 删除 json 文件中的特定内容
- ruby-on-rails - 由 ujs 导致的 Rails Scaffolds 未提交表单(表单卡在新上)
- forms - XLSForm、ODK XForm 和 XForms 是等效的吗?
- c - 编译 Ubuntu 20.04 时找不到库函数
- node.js - 如何将输入数据存储到数组选项中?