gpt4 book ai didi

java - 可嵌入对象未持久保存到辅助表中

转载 作者:行者123 更新时间:2023-12-01 17:11:34 30 4
gpt4 key购买 nike

在我的真实项目中,有一个具有约 15 个属性(列)的实体。我需要存储大约 10 个与实体相关的属性。为了避免在同一个表中创建新列,一种方法是将新属性存储在另一个实体中,并通过一对一关系将它们链接起来。 Here我找到了另一种方法,这意味着将可嵌入对象存储在辅助表中。问题在于,具有未初始化属性的可嵌入对象不会持久化到数据库中。我已在 demo project 中重现了该问题:

@Entity
@Table(name = "STUDENTS")
@SecondaryTable(
name = ADDRESSES,
pkJoinColumns = @PrimaryKeyJoinColumn(name = "STUDENT_ID")
)
public class Student {

@Id
@GeneratedValue
private Long id;

private String firstName;
private String lastName;

@Embedded // not needed
private Address address;

//constructors, getters and setters
<小时/>
@Embeddable
public class Address {

public static final String ADDRESSES = "ADDRESSES";

@Column(table = ADDRESSES)
private String country;
@Column(table = ADDRESSES)
private String city;
@Column(table = ADDRESSES)
private String street;
@Column(table = ADDRESSES)
private Integer houseNumber;

//constructors, getters and setters
<小时/>
@Service
@Transactional
public class StudentService {

@Autowired
private StudentRepository studentRepository;

@Transactional(readOnly = true)
public List<Student> findAll() {
return studentRepository.findAll();
}

public Student createStudentWithEmptyAddress() {
Student student = new Student("Caleb", "Baker", new Address());
return studentRepository.save(student);
}

public Student createStudentWithNonEmptyAddress() {
Address address = new Address("France", "Paris", "Rue Vieille Du Temple", 88);
Student student = new Student("Cayden", "Hoover", address);
return studentRepository.save(student);
}

public Student findById(Long id) {
return studentRepository
.findById(id)
.orElseThrow(() -> new RuntimeException("Student with id: " + id + " was not found"));
}

public Student updateStudentWithEmptyAddress(Long id) {
Student student = findById(id);
student.setAddress(new Address());
return student;
}

public Student updateStudentWithNonEmptyAddress(Long id) {
Student student = findById(id);
Address address = new Address("USA", "New York", "Stanton Street", 17);
student.setAddress(address);
return student;
}

}
<小时/>
@RestController
@RequestMapping("/student")
public class StudentController {

@Autowired
private StudentService studentService;

@GetMapping("/all")
@ResponseStatus(OK)
public List<Student> findAll() {
return studentService.findAll();
}

@GetMapping("/{id}")
@ResponseStatus(OK)
public Student findOne(@PathVariable Long id) {
return studentService.findById(id);
}

@PostMapping("/emptyAddress")
@ResponseStatus(CREATED)
public Student createStudentWithEmptyAddress() {
return studentService.createStudentWithEmptyAddress();
}

@PostMapping("/nonEmptyAddress")
@ResponseStatus(CREATED)
public Student createStudentWithNonEmptyAddress() {
return studentService.createStudentWithNonEmptyAddress();
}

@PutMapping("/{id}/emptyAddress")
@ResponseStatus(OK)
public Student updateStudentWithEmptyAddress(@PathVariable Long id) {
return studentService.updateStudentWithEmptyAddress(id);
}

@PutMapping("/{id}/nonEmptyAddress")
@ResponseStatus(OK)
public Student updateStudentWithNonEmptyAddress(@PathVariable Long id) {
return studentService.updateStudentWithNonEmptyAddress(id);
}
}
<小时/>

POST localhost:8080/student/nonEmptyAddress 返回预期输出:

jdbc.sqlonly: insert into students (first_name, last_name, id) values ('Cayden', 'Hoover', 4) 
jdbc.sqlonly: insert into addresses (city, country, house_number, street, student_id) values ('Paris', 'France', 88, 'Rue Vieille Du Temple', 4)
<小时/>
{
"id": 4,
"firstName": "Cayden",
"lastName": "Hoover",
"address": {
"country": "France",
"city": "Paris",
"street": "Rue Vieille Du Temple",
"houseNumber": 88
}
}
<小时/>

GET localhost:8080/student/4 返回上面的结果。现在让我们创建一个带有 Address 对象的学生,其中所有属性均未初始化:

POST localhost:8080/student/nonEmptyAddress 返回预期输出:

jdbc.sqlonly: insert into students (first_name, last_name, id) values ('Caleb', 'Baker', 5)
jdbc.sqlonly: insert into addresses (city, country, house_number, street, student_id) values (NULL, NULL, NULL, NULL, 5)
<小时/>
{
"id": 5,
"firstName": "Caleb",
"lastName": "Baker",
"address": {
"country": null,
"city": null,
"street": null,
"houseNumber": null
}
}

但是,当我调用 GET 端点时,我收到另一个结果。获取本地主机:8080/student/5:

jdbc.sqlonly: select student0_.id as id1_1_0_, student0_.first_name as first_na2_1_0_, student0_.last_name as last_nam3_1_0_, student0_1_.city as city1_0_0_, student0_1_.country as country2_0_0_, student0_1_.house_number as house_nu3_0_0_, student0_1_.street as street4_0_0_ from students student0_ left outer join addresses student0_1_ on student0_.id=student0_1_.student_id where student0_.id=5
<小时/>
{
"id": 5,
"firstName": "Caleb",
"lastName": "Baker",
"address": null
}
<小时/>
Content of ADRESSES table:
CITY COUNTRY HOUSE_NUMBER STREET STUDENT_ID
Paris France 88 Rue Vieille Du Temple 4
null null null null 5

尽管 ADRESSES 表中存在第二条记录,但地址为空。当 Address 对象中至少有一个初始化属性时,用地址更新学生可以按预期进行。但是,如果您使用所有属性都为空的地址更新学生 (PUT localhost:8080/student/3/emptyAddress),则表 ADDRESSES 甚至不会被更新。

上面的例子有什么问题吗?我认为使用 @Embeddable 和 @Secondary 表来达到预期结果不是正确的方法。

最佳答案

在将类实现为 @Embeddable 时,Hibernate 会在该表上创建一个左外连接,仅选择四个可为空的字段。因为这些值为 null,所以不会返回任何内容,并且对象也为 null(尽管它们是表中的记录)。

尝试在Address表中使用@Column添加字段的外键映射。由于此列始终被填充,因此尽管所有字段都为空,查询仍会选取整行并正确构造对象。

关于java - 可嵌入对象未持久保存到辅助表中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61425177/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com