Java.lang.IllegalArgumentException: ожидается отображение IdClass
Я сконфигурировал составной первичный ключ для моего объекта Employee
следующим образом
Employee.java:
@Entity
@Table(name="employee")
@Proxy(lazy=false)
@IdClass(EmployeeId.class)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private EmployeeId employeeId;
private Person person;
private Branch branch;
private boolean isActive;
public Employee() {
}
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name="person", column = @Column(name="person_id")),
@AttributeOverride(name="branch", column = @Column(name="branch_id"))})
public EmployeeId getEmployeeId() {
return employeeId;
}
public void setEmployeeId(EmployeeId employeeId) {
this.employeeId = employeeId;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="person_id")
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="branch_id")
public Branch getBranch() {
return branch;
}
public void setBranch(Branch branch) {
this.branch = branch;
}
@Column(name="is_active")
public boolean getIsActive() {
return isActive;
}
public void setIsActive(boolean isActive) {
this.isActive = isActive;
}
}
EmployeeId.java:
@Embeddable
public class EmployeeId implements Serializable {
private static final long serialVersionUID = 1L;
private Person person;
private Branch branch;
public EmployeeId() {
}
public EmployeeId(Person argPerson, Branch argbranch) {
this.person = argPerson;
this.branch = argbranch;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="person_id", insertable=false, updatable=false)
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="branch_id", insertable=false, updatable=false)
public Branch getBranch() {
return branch;
}
public void setBranch(Branch branch) {
this.branch = branch;
}
}
Я создал SessionFactory
bean с помощью класса org.springframework.orm.hibernate5.LocalSessionFactoryBean
и отобразил все hbm.xml
как MappingLocations
.
Мой код вызывает следующую ошибку:
Caused by: java.lang.IllegalArgumentException: expecting IdClass mapping
at org.hibernate.metamodel.internal.AttributeFactory$3.resolveMember(AttributeFactory.java:971)
at org.hibernate.metamodel.internal.AttributeFactory$5.resolveMember(AttributeFactory.java:1029)
at org.hibernate.metamodel.internal.AttributeFactory.determineAttributeMetadata(AttributeFactory.java:451)
at org.hibernate.metamodel.internal.AttributeFactory.buildIdAttribute(AttributeFactory.java:128)
at org.hibernate.metamodel.internal.MetadataContext.buildIdClassAttributes(MetadataContext.java:337)
at org.hibernate.metamodel.internal.MetadataContext.applyIdMetadata(MetadataContext.java:269)
at org.hibernate.metamodel.internal.MetadataContext.wrapUp(MetadataContext.java:190)
at org.hibernate.metamodel.internal.MetamodelImpl.initialize(MetamodelImpl.java:219)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:296)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:476)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:707)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:723)
at org.springframework.orm.hibernate5.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:504)
at org.springframework.orm.hibernate5.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:488)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFac
Как я могу избежать этой ошибки? Я использую spring-orm-4.3.1-RELEASE
и hibernate-core-5.2.0.Final
.
Обновление
Я создал образец проекта, и во время работы я получаю следующую ошибку...
Caused by: org.hibernate.AnnotationException: Property of @IdClass not found in entity sample.domain.Employee: employee
Обратитесь к коду: https://www.dropbox.com/s/axr8l01iqh0qr29/idclass-using-hibernate5.tar.gz?dl=0
Что я сделал не так? Пожалуйста, предоставьте свои данные здесь.
Ответы
Ответ 1
Сопоставление композитных клавиш может быть выполнено с помощью IdClass или Embeddable. Если вы хотите использовать IdClass, вы должны аннотировать свои поля в Employee с помощью @Id.
@IdClass(EmployeeId.class)
class Person{
@Id
private Person person;
@Id
private Branch branch;
}
Если вы хотите использовать встроенный как составной ключ, удалите аннотацию @IdClass (EmployeeId.class) от Person. Вам также не нужно поле person и branch в вашем классе Person, потому что они определены в вашем классе Embedded.
Ответ 2
Ваша ситуация соответствует главе 2.4.1 Первичные ключи, соответствующие производным тождествам Спецификация JPA 2.1.
Личность Employee
выводится из тождеств Person
и Branch
. Вы не указали код ни одного из них, поэтому я предполагаю, что у них простые первичные ключи. В этом отношении Person
и Branch
являются "родительскими объектами", а Employee
является "зависимым" объектом.
Идентификатор Employee
может отображаться с использованием либо IdClass
, либо EmbeddedId
, но не одновременно.
См. главу 2.4.1.1. Спецификация производных идентификаторов.
Если вы хотите использовать IdClass
, то:
Имена атрибутов класса id и атрибутов Id зависимого класса сущностей должны соответствовать следующим образом:
- Атрибут
Id
в классе сущности и соответствующий атрибут в классе id должны иметь одинаковое имя.
...
- Если атрибут
Id
в объекте является отношением "много к одному" или "один к одному" к родительскому объекту, соответствующий атрибут в классе id должен иметь (...) тип Id
атрибута родительского объекта.
Итак, ваши классы будут выглядеть так: (геттеры, сеттеры, лишние аннотации и т.д. опущены)
@Entity
@IdClass(EmployeeId.class)
public class Employee {
@Id
@ManyToOne
private Person person;
@Id
@ManyToOne
private Branch branch;
}
public class EmployeeId {
private Long person; // Corresponds to the type of Person ID, name matches the name of Employee.person
private Long branch; // Corresponds to the type of Branch ID, name matches the name of Employee.branch
}
Если вы используете EmbeddedId
, то:
Если зависимый объект использует встроенный идентификатор для представления его первичного ключа, атрибут во встроенном идентификаторе, соответствующий атрибуту отношения, должен быть того же типа, что и первичный ключ родительского объекта, и должен быть обозначен символом MapsId
аннотации к атрибуту отношения. Элемент value
аннотации MapsId
должен использоваться для указания имени атрибута во встроенном идентификаторе, которому соответствует атрибут отношения.
И код будет выглядеть так:
@Entity
public class Employee {
@EmbeddedId
private EmployeeId id;
@ManyToOne
@MapsId("personId") // Corresponds to the name of EmployeeId.personId
private Person person;
@ManyToOne
@MapsId("branchId") // Corresponds to the name of EmployeeId.branchId
private Branch branch;
}
@Embeddable
public class EmployeeId {
private Long personId; // Corresponds to the type of Person ID
private Long branchId; // Corresponds to the type of Branch ID
}
Ответ 3
Изменить на:
@Entity
@Table(name = "employee")
@Proxy(lazy = false)
@IdClass(EmployeeId.class)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private EmployeeId id;
private Person person;
private Branch branch;
private boolean isActive;
public Employee() {
}
@EmbeddedId
@AttributeOverrides({@AttributeOverride(name = "person", column = @Column(name = "person_id") ),
@AttributeOverride(name = "branch", column = @Column(name = "branch_id") )})
public EmployeeId getId() {
return id;
}
public void setId(EmployeeId id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "person_id")
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "branch_id")
public Branch getBranch() {
return branch;
}
public void setBranch(Branch branch) {
this.branch = branch;
}
@Column(name = "is_active")
public boolean getIsActive() {
return isActive;
}
public void setIsActive(boolean isActive) {
this.isActive = isActive;
}
}
Ответ 4
IdClass не должен определяться как Embeddable -
@Entity
@Table(name="employee")
@IdClass(EmployeeId.class)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@ManyToOne
private Person person;
@Id
@ManyToOne
private Branch branch;
private boolean isActive;
public Employee() { }
//....
}
И -
public class EmployeeId implements Serializable {
private static final long serialVersionUID = 1L;
private Person person;
private Branch branch;
public EmployeeId() {}
public EmployeeId(Person argPerson, Branch argbranch) {
this.person = argPerson;
this.branch = argbranch;
}
}
Прочитайте свой комментарий. Могу ли я сделать предложение о том, что вы сопоставляете Employee с person_id и branch_id, а не с объектами JPA Person и Branch? Это позволит нам проверить правильность конфигурации hbm. Id также предлагает разместить вашу конфигурацию hbm, поскольку я думаю, что в этой проблеме отсутствует информация.
Таким образом, таблица будет похожа на -
@Entity
@Table(name="employee")
@IdClass(EmployeeId.class)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private Long personId;
@Id
private Long branchId;
private boolean isActive;
public Employee() { }
//....
}
И -
И -
public class EmployeeId implements Serializable {
private static final long serialVersionUID = 1L;
private Long personId;
private Long branchId;
public EmployeeId() {}
public EmployeeId(Person argPerson, Branch argbranch) {
this.person = argPerson;
this.branch = argbranch;
}
}
Ответ 5
Обозначает @IdClass
аннотацию с классом, который содержит ID
.
Ответьте на
Ответ 6
Эта ссылка может помочь вам
JPA - EmbeddedId с @ManytoOne
Отображения связей, определенные во встроенном классе id, не поддерживаются. Затем вам нужно изменить класс embeddedId следующим образом
@Embeddable
public class EmployeeId implements Serializable {
private static final long serialVersionUID = 1L;
private Long personId;
private Long branchId;
public EmployeeId() {
}
public EmployeeId(Long argPerson, Long argbranch) {
this.personId = argPerson;
this.branchId = argbranch;
}
@Column(name = "person_id")
public Long getPersonId() {
return personId;
}
public void setPersonId(Long personId) {
this.personId = personId;
}
@Column(name = "branch_id")
public Long getBranchId() {
return branchId;
}
public void setBranchId(Long branchId) {
this.branchId = branchId;
}
}
Ответ 7
Основной символ JPA Composite
Задает составной класс первичного ключа, который сопоставляется с несколькими полями или свойствами объекта.
Имена полей или свойств в классе первичного ключа и поля первичного ключа или свойства объекта должны соответствовать и их типы должны быть одинаковыми.
Ответ здесь. прочитайте описание для вас. введите ссылку здесь
(Пример кода)
@Entity
@Table(name = "EMP_PROJECT")
@IdClass(ProjectAssignmentId.class)
public class ProjectAssignment {
@Id
@Column(name = "EMP_ID", insertable = false, updatable = false)
private int empId;
@Id
@Column(name = "PROJECT_ID", insertable = false, updatable = false)
private int projectId;
@ManyToOne
@JoinColumn(name = "EMP_ID")
Professor employee;
@ManyToOne
@JoinColumn(name = "PROJECT_ID")
Project project;
....
}
public class ProjectAssignmentId implements Serializable {
private int empId;
private int projectId;
...
}