Hibernate 5 Java двунаправленное поле oneToMany пусто, но таблица содержит данные - PullRequest
0 голосов
/ 13 сентября 2018

У меня есть две организации: отдел и сотрудник.Отдел имеет список сотрудников.А у сотрудника есть полевой отдел.Я могу создавать сотрудников и добавлять их в список внутри отдела.Таблицы базы данных заполнены, как и ожидалось, сохраняются.Если я запрашиваю отдел, я получаю отдел, и список сотрудников заполняется.Все хорошо, таким образом.Если я запрашиваю Employee и получаю поле Department, оно возвращает null.

@Entity
@Table(name = "DEPARTMENT")
public class Department {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "DPT_ID")
    private long id;

    @Column(name = "NAME", nullable = false, unique = true)
    private String name;


    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "DEPARTMENT") //we need to duplicate the physical information
    private List<Employee> employees = new ArrayList<>();
…

-

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "EMP_ID")
    private long id;

    @Column(name = "NAME", nullable = false)
    private String name;

    @Column(name = "DESIGNATION")
    private String designation;

    @ManyToOne
    @JoinColumn(name = "DEPARTMENT", insertable = false, updatable = false)
    private Department department;
...

-

Запрос, где employee.getDepartment () return null

        session = HibernateUtil.getSessionFactory().openSession();
        transaction = session.getTransaction();
        transaction.begin();

        Department department = new Department();
        department.setName("IT Department");

        Employee employee1 = new Employee();
        employee1.setName("Adam");
        employee1.setDesignation("Manager");

        Employee employee2 = new Employee();
        employee2.setName("Miller");
        employee2.setDesignation("Software Engineer");

        Employee employee3 = new Employee();
        employee3.setName("Smith");
        employee3.setDesignation("Associate  Engineer");

        department.getEmployees().add(employee1);
        department.getEmployees().add(employee2);
        department.getEmployees().add(employee3);

        session.persist(department);
        session.flush();
        transaction.commit();


        transaction = session.getTransaction();
        transaction.begin();

        {
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<Employee> query = builder.createQuery(Employee.class);
            Root<Employee> root = query.from(Employee.class);
            query.select(root);
            Query<Employee> q = session.createQuery(query);
            List<Employee> employees = q.getResultList();
            for (Employee employee : employees) {
                System.out.println("EMPLOYEE NAME: " + employee.getName());
                System.out.println("DEPARTMENT NAME: " + employee.getDepartment()); // gives null
            }
        }
        {
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<Department> query = builder.createQuery(Department.class);
            Root<Department> root = query.from(Department.class);
            query.select(root);
            Query<Department> q = session.createQuery(query);
            List<Department> departments = q.getResultList();
            for (Department deps : departments) {
                System.out.println(deps.getName());
                System.out.println(deps.getEmployees()); // list of employees is filled
            }
        }

Department table Employee Table

Таблицы заполнены правильно.Но если я использую getDepartment для запрашиваемого сотрудника, я получаю нулевое значение.Если я использую getEmployees в запрашиваемом отделе, я получаю всех сотрудников.

Я попробовал оба способа, описанные здесь: https://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/ch07.html#collections-bidirectional

Пример 7.21.Двунаправленный один ко многим, многие из которых в одну сторону являются владельцами ассоциаций

и

Пример 7.22.Двунаправленная ассоциация со стороной один ко многим в качестве владельца

Тот же результат для меня.

Чего мне не хватает?

Вот полный тестовый проект: обновлен Project zip

РЕШЕННЫЙ ФИКСИРОВАННЫЙ ПРОЕКТ: РЕШЕННЫЙ ПРОБЛЕМА ПРОЕКТ

Ответы [ 4 ]

0 голосов
/ 14 сентября 2018

Я нашел проблему.Я использовал тот же сеанс для сохранения и запроса.

session = HibernateUtil.getSessionFactory().openSession();
transaction = session.getTransaction();
transaction.begin();
…
session.persist(stuff);
session.flush();
transaction.commit();

transaction = session.getTransaction();
transaction.begin();

query stuff

Если я закрываю сеанс после сохранения и открываю новый сеанс, все работает нормально.

Я добавил исправленную версию тестаПроецируй на мой вопрос только на случай, если кто-то заинтересован.

0 голосов
/ 14 сентября 2018

Похоже, проблема Owning entity, поэтому я думаю, что ваш тест сохраняет данные двумя разными способами.В вашей аннотации @OneToMany(cascade = CascadeType.ALL) вы объявили Department владельцем отношений.Таким образом, если вы сохраните данные с помощью

dept.getEmployees().add(emp);

, тогда поле отдела (id) будет обновлено

Hibernate: insert into EMPLOYEE (EMP_ID, DESIGNATION, NAME) values (null, ?, ?)
Hibernate: update EMPLOYEE set DEPARTMENT=? where EMP_ID=?

, но если вы сохраните с помощью

emp.setDepartment(dept);

, тогдаполе отдела (id) сотрудника не будет обновлено.

Hibernate: insert into EMPLOYEE (EMP_ID, DESIGNATION, NAME) values (null, ?, ?)

Если идентификатор сотрудника отдела не сохранен, вы не можете получить отдел.Это более эффективно, если вы сделаете Employee владельцем отношений, поскольку он имеет внешний ключ.

@OneToMany(cascade = CascadeType.ALL, mappedBy="department")
private List<Employee> employees; // don't need to make a list, only for fetches
// and 
@ManyToOne
@JoinColumn(name = "DEPARTMENT")
private Department department;

и задаете отдел сотрудника при сохранении отношений.Затем вставка выполняется с помощью detamentid и не обновляется отдельно.

Hibernate: insert into EMPLOYEE (EMP_ID, DEPARTMENT, DESIGNATION, NAME) values (null, ?, ?, ?)

В коде критерия нет ничего явно неправильного, поскольку JPA будет следовать аннотированным отношениям, но это происходит в двух отдельных запросах, поскольку вы неу него нет определенного объединения.

Hibernate: select employee0_.EMP_ID as EMP_ID1_1_, employee0_.DEPARTMENT as DEPARTME4_1_, employee0_.DESIGNATION as DESIGNAT2_1_, employee0_.NAME as NAME3_1_ from EMPLOYEE employee0_
Hibernate: select department0_.DPT_ID as DPT_ID1_0_0_, department0_.NAME as NAME2_0_0_ from DEPARTMENT department0_ where department0_.DPT_ID=?

Если вы добавите конкретную выборку, то это будет сделано в одном выражении SQL.

root.fetch("department");

и

Hibernate: select employee0_.EMP_ID as EMP_ID1_1_0_, department1_.DPT_ID as DPT_ID1_0_1_, employee0_.DEPARTMENT as DEPARTME4_1_0_, employee0_.DESIGNATION as DESIGNAT2_1_0_, employee0_.NAME as NAME3_1_0_, department1_.NAME as NAME2_0_1_ from EMPLOYEE employee0_ inner join DEPARTMENT department1_ on employee0_.DEPARTMENT=department1_.DPT_ID
0 голосов
/ 14 сентября 2018

На мой взгляд, ваше реляционное отображение неверно! Попробуйте изменить код следующим образом.

@ManyToOne
@JoinColumn(name = "DEPT_ID")
private Department department;


@OneToMany(mappedBy = "department",cascade = CascadeType.ALL)
private List<Employee> employees = new ArrayList<>();
0 голосов
/ 13 сентября 2018

попробуйте с помощью следующего кода, просто укажите таблицу соединений на Отдел от Сотрудника.

@ManyToOne
@JoinColumn(name = "DPT_ID", insertable = false, updatable = false)
private Department department;
...