Встраиваемый объект не сохраняется во вторичной таблице - PullRequest
0 голосов
/ 25 апреля 2020

В моем реальном проекте есть сущность с ~ 15 свойствами (столбцами). Мне нужно хранить еще около 10 свойств, связанных с сущностью. Чтобы избежать создания новых столбцов в той же таблице, один из подходов заключается в том, чтобы сохранить новые свойства в другом объекте и связать их с отношением «один к одному». Здесь Я нашел другой подход, который подразумевает сохранение объекта emdebbable во вторичной таблице. Проблема в том, что встраиваемый объект с неинициализированными свойствами не сохраняется в базе данных. Я воспроизвел проблему в демонстрационном проекте :

@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, я получаю другой результат. GET localhost: 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. Обновление учащегося с помощью адреса, когда в объекте адреса есть хотя бы одно инициализированное свойство, работает должным образом. Однако если вы обновите учащегося по адресу, в котором все свойства будут нулевыми (PUT localhost: 8080 / student / 3 / emptyAddress), то таблица ADDRESSES даже не обновляется.

Что не так в примере над? Я предполагаю, что неправильно использовать @Embeddable и @Secondary table для достижения желаемого результата.

1 Ответ

0 голосов
/ 25 апреля 2020

Реализуя класс как @Embeddable, Hibernate создает левое внешнее объединение для этой таблицы, выбирая только четыре поля, которые можно обнулять. Поскольку эти значения являются нулевыми, ничего не возвращается, а объект является нулевым (несмотря на то, что они являются записями в таблице).

Попробуйте добавить сопоставление внешнего ключа поля, используя @Column в таблице адресов. Поскольку этот столбец всегда заполнен, запрос выбирает всю строку и правильно создает объект, несмотря на то, что все поля имеют значение null.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...