OnetoOne Двунаправленная ассоциация Ошибка при использовании referenceColumnName

Компания

@Entity
@Table(name="company")

public class Company implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private int id;

    @Column(name="company_id")
    private int cmpId;

    @Column(name="company_name")
    private String companyName;

    @OneToOne(fetch=FetchType.LAZY, mappedBy="company")
    private Employee employee;




}

Сущность сотрудника

@Entity
@Table(name="employee")
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private int id;

    @Column(name="emp_id")
    private int empId;

    @Column(name="emp_name")
    private String empName;

    @OneToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="cmp_id", referencedColumnName="company_id")
    private Company company;

}

Сервис компании

@Service
public class CompanyService {

    @Autowired
    private CompanyRepository companyRepo;

    public Company fetchCompany(int cmpId){
        System.out.println("11111111111111111");
        return companyRepo.findByCmpId(cmpId);
    }
}

Компания Repo

public interface CompanyRepository extends JpaRepository<Company, Integer>{ 

    @Query(value="select a from Company a join fetch a.employee where a.cmpId = ?1")
    public Company findByCmpId(int cmpId);
}

API

@RequestMapping("/cmp/{cmpId}")
public void findCmp(@PathVariable int cmpId){
    Company cmp = cmpService.fetchCompany(cmpId);
    System.out.println(cmp.getEmployee().getEmpName());
}

Проблема в том, что когда я пытаюсь выполнить мой код, я получаю следующую ошибку:

  Hibernate: select company0_.id as id1_1_0_, employee1_.id as id1_2_1_, company0_.company_id as company_2_1_0_, company0_.company_name as company_3_1_0_, employee1_.cmp_id as cmp_id4_2_1_, employee1_.emp_id as emp_id2_2_1_, employee1_.emp_name as emp_name3_2_1_ from company company0_ inner join employee employee1_ on company0_.id=employee1_.cmp_id where company0_.company_id=?
2017-04-21 17:22:11.386 ERROR 10766 --- [nio-8105-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: Error accessing field [private int com.example.domain.Company.cmpId] by reflection for persistent property [com.example.domain.Company#cmpId] : 1; nested exception is org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private int com.example.domain.Company.cmpId] by reflection for persistent property [com.example.domain.Company#cmpId] : 1] with root cause

java.lang.IllegalArgumentException: Can not set int field com.example.domain.Company.cmpId to java.lang.Integer
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167) ~[na:1.8.0_91]
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171) ~[na:1.8.0_91]
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58) ~[na:1.8.0_91]
    at sun.reflect.UnsafeIntegerFieldAccessorImpl.getInt(UnsafeIntegerFieldAccessorImpl.java:56) ~[na:1.8.0_91]
    at sun.reflect.UnsafeIntegerFieldAccessorImpl.get(UnsafeIntegerFieldAccessorImpl.java:36) ~[na:1.8.0_91]
    at java.lang.reflect.Field.get(Field.java:393) ~[na:1.8.0_91]

Как это исправить? Кроме того, когда я удалил referenceColumnName, тогда ошибка будет удалена, но они будут объединены с первичным ключом корпоративного класса, чего я не хочу.

Ответы

Ответ 1

Это выглядит немного напуганным, но я считаю, что он работает так, как вы просили.

Компания

@Entity
@Table(name = "company")
public class Company implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Integer id;

    @Column(name = "comp_id")
    private Integer compId;

    @Column(name = "company_name")
    private String companyName;

    @OneToOne
    @JoinColumn(name="emp_id", referencedColumnName="emp_id")
    private Employee employee;

    @PostPersist
    public void postPersist() {
        if (id != null && compId == null) {
            setCompId(new Integer(id));
        }
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

    public Integer getCompId() {
        return compId;
    }

    public void setCompId(Integer compId) {
        this.compId = compId;
    }
}

CompanyRepository

public interface CompanyRepository extends JpaRepository<Company, Integer> {

    @Query(value = "select a from Company a join fetch a.employee as emp where a.compId = ?1")
    public Company findByCmpId(int cmpId);
}

CompanyService

@Service
public class CompanyService {

    @Autowired
    private CompanyRepository companyRepo;

    public Company fetchCompany(int cmpId) {
        return companyRepo.findByCmpId(cmpId);
    }
}

Сотрудник

@Entity
@Table(name = "employee")
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Integer id;

    @Column(name = "emp_id")
    private Integer empId;

    @Column(name = "emp_name")
    private String empName;

    @OneToOne
    @JoinColumn(name="comp_id", referencedColumnName="comp_id")
    private Company company;

    @PostPersist
    public void postPersist() {
        if (id != null && empId == null) {
            setEmpId(new Integer(id));
        }
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getEmpId() {
        return empId;
    }

    public void setEmpId(Integer empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }
}

EmployeeRepository

public interface EmployeeRepository extends JpaRepository<Employee, Integer> 
{
    @Query(value = "select a from Employee a join fetch a.company as comp where a.empId = ?1")
    public Employee findByEmpId(int cmpId);
}

EmployeeService

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository employeeRepo;

    public Employee fetchEmployee(int empId) {
        return employeeRepo.findByEmpId(empId);
    }
}

Тесты устройств

@RunWith(SpringRunner.class)
@SpringBootTest
public class RnlApplicationTests {

    @Autowired
    CompanyService companyService;

    @Autowired
    EmployeeService employeeService;

    @Autowired
    CompanyRepository companyRepository;

    @Autowired
    EmployeeRepository employeeRepository;

    @Before 
    public void setup() {
        Employee employee = new Employee();
        employee.setEmpName("Test Employee");

        Company company = new Company();
        company.setCompanyName("Test Company");
        company = companyRepository.save(company);

        employee.setCompany(company);
        employee = employeeRepository.save(employee);

        company.setEmployee(employee);
        company = companyRepository.save(company);

        Employee employee2 = new Employee();
        employee2.setEmpName("Test Employee2");

        Company company2 = new Company();
        company2.setCompanyName("Test Company2");
        company2 = companyRepository.save(company2);

        employee2.setCompany(company2);
        employee2 = employeeRepository.save(employee2);

        company2.setEmployee(employee2);
        company2 = companyRepository.save(company2);
    }

    @Test
    public void testRepository() {
        Company company = companyService.fetchCompany(1);
        assertThat(company).isNotNull();

        Company company2 = companyService.fetchCompany(2);
        assertThat(company2).isNotNull();

        Employee employee = employeeService.fetchEmployee(1);
        assertThat(employee).isNotNull();

        Employee employee2 = employeeService.fetchEmployee(2);
        assertThat(employee2).isNotNull();
    }
}

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

Выход Hibernate SQL из теста компании

select
    company0_.id as id1_0_2_,
    company0_.comp_id as comp_id2_0_2_,
    company0_.company_name as company_3_0_2_,
    company0_.emp_id as emp_id4_0_2_,
    employee1_.id as id1_1_0_,
    employee1_.comp_id as comp_id4_1_0_,
    employee1_.emp_id as emp_id2_1_0_,
    employee1_.emp_name as emp_name3_1_0_,
    company2_.id as id1_0_1_,
    company2_.comp_id as comp_id2_0_1_,
    company2_.company_name as company_3_0_1_,
    company2_.emp_id as emp_id4_0_1_ 
from
    company company0_ 
left outer join
    employee employee1_ 
        on company0_.emp_id=employee1_.emp_id 
left outer join
    company company2_ 
        on employee1_.comp_id=company2_.comp_id 
where
    company0_.comp_id=?

Выход Hibernate SQL из теста Employee

select
    employee0_.id as id1_1_0_,
    company1_.id as id1_0_1_,
    employee0_.comp_id as comp_id4_1_0_,
    employee0_.emp_id as emp_id2_1_0_,
    employee0_.emp_name as emp_name3_1_0_,
    company1_.comp_id as comp_id2_0_1_,
    company1_.company_name as company_3_0_1_,
    company1_.emp_id as emp_id4_0_1_ 
from
    employee employee0_ 
inner join
    company company1_ 
        on employee0_.comp_id=company1_.comp_id 
where
    employee0_.emp_id=?

Ответ 2

Исключение:

 IllegalArgumentException: Can not set int field com.example.domain.Company.cmpId to java.lang.Integer

Пожалуйста, используйте Integer instead of int в компании как мы, как в сущности Employee, если поле id.

 @Id
    @GeneratedValue
    private Integer id;

Также укажите методы получения и настройки для полей в вашей организации.

Ответ 3

**Can not set int field com.example.domain.Company.cmpId to java.lang.Integer**

Hibernate except foreign key of employee table cmp_id, should be primary key of company. But in your code cmpId is not primary key.

        @Column(name="company_id")
        private int cmpId;

Please make that primary and check once.


Edited:-
1.
        @OneToOne(fetch=FetchType.LAZY, mappedBy="company")
        private Employee employee;
change to:-
        @OneToOne(fetch=FetchType.LAZY, mappedBy="company",optional=false)
        private Employee employee;

2.
        @OneToOne(fetch=FetchType.LAZY)
        @JoinColumn(name="cmp_id", referencedColumnName="company_id")
        private Company company;
change to:-
        @OneToOne(fetch=FetchType.LAZY)
        @JoinColumn(name="cmp_id")
        private Company company;