为什么实现 Hibernate @OneToMany 关系时出现此错误? “实体映射中的重复列:XXX.Address 列:id”
Why implementing an Hibernate @OneToMany relationship I am obtaining this error? " Repeated column in mapping for entity: XXX.Address column: id"
我正在使用 Spring Data JPA 开发 Spring 引导应用程序,我发现在实施 Hibernate 映射时出现以下问题。
基本上我首先在我的数据库上创建了 tables,然后我创建了映射这些 table 的实体 classes(在我的项目中,数据库 tables 是不是从实体自动生成的 classes).
我有这两个数据库 tables:
portal_user:这是主要的 table 包含代表门户用户的记录。
CREATE TABLE IF NOT EXISTS public.portal_user
(
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
first_name character varying(50) COLLATE pg_catalog."default" NOT NULL,
middle_name character varying(50) COLLATE pg_catalog."default",
surname character varying(50) COLLATE pg_catalog."default" NOT NULL,
sex "char" NOT NULL,
birthdate date NOT NULL,
tex_code character varying(50) COLLATE pg_catalog."default" NOT NULL,
e_mail character varying(50) COLLATE pg_catalog."default" NOT NULL,
contact_number character varying(50) COLLATE pg_catalog."default" NOT NULL,
created_at date NOT NULL,
CONSTRAINT user_pkey PRIMARY KEY (id)
)
address:它包含代表以前用户地址的记录。每个用户可以有一个或多个地址。
CREATE TABLE IF NOT EXISTS public.address
(
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
country character varying(50) COLLATE pg_catalog."default" NOT NULL,
province character varying(50) COLLATE pg_catalog."default" NOT NULL,
zip_code character varying(5) COLLATE pg_catalog."default" NOT NULL,
street character varying(250) COLLATE pg_catalog."default" NOT NULL,
notes character varying(250) COLLATE pg_catalog."default",
fk_user_id bigint NOT NULL,
CONSTRAINT address_pkey PRIMARY KEY (id),
CONSTRAINT fk_user_id FOREIGN KEY (fk_user_id)
REFERENCES public.portal_user (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
NOT VALID
)
如您所见,每个用户可以拥有一个或多个地址,因此 portal_user 和 地址 之间的关系是 ONE TO MANY(因为一个用户可以有多个地址)。要实现此行为,address 包含 fk_user_id 字段,表示特定 portal_user 的 ID 记录。
好的,那么我将尝试使用 Hibernate 映射这两个 table 及其关系。
首先我创建了 User 实体 class:
@Entity
@Table(name = "portal_user")
@Data
public class User implements Serializable {
private static final long serialVersionUID = 5062673109048808267L;
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "middle_name")
private String middleName;
@Column(name = "surname")
private String surname;
@Column(name = "sex")
private char sex;
@Column(name = "birthdate")
private Date birthdate;
@Column(name = "tex_code")
private String taxCode;
@Column(name = "e_mail")
private String eMail;
@Column(name = "contact_number")
private String contactNumber;
@Temporal(TemporalType.DATE)
@Column(name = "created_at")
private Date createdAt;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
@JsonManagedReference
private Set<Address> addressesList = new HashSet<>();
public User(String firstName, String middleName, String surname, char sex, Date birthdate, String taxCode,
String eMail, String contactNumber, Date createdAt) {
super();
this.firstName = firstName;
this.middleName = middleName;
this.surname = surname;
this.sex = sex;
this.birthdate = birthdate;
this.taxCode = taxCode;
this.eMail = eMail;
this.contactNumber = contactNumber;
this.createdAt = createdAt;
}
}
如您所见,此 class 包含定义到 portal_user 数据库 table 和此 中的所有字段OneToMany 关系。基本上它说一个用户与多个地址相关:
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
@JsonManagedReference
private Set<Address> addressesList = new HashSet<>();
然后我创建了 Address 实体 class 映射我的数据库 address table,这个:
@Entity
@Table(name = "address")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address implements Serializable {
private static final long serialVersionUID = 6956974379644960088L;
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name = "country")
private String country;
@Column(name = "province")
private String province;
@Column(name = "zip_code")
private String zipCode;
@Column(name = "street")
private String street;
@Column(name = "notes")
private String notes;
//@Column(name = "fk_user_id")
//private int fkUserId;
@ManyToOne
@EqualsAndHashCode.Exclude // Needed by Lombock in "Many To One" relathionship to avoid error
@JoinColumn(name = "id", referencedColumnName = "id")
@JsonBackReference
private User user;
public Address(String country, String province, String zipCode, String street, String notes, User user) {
super();
this.country = country;
this.province = province;
this.zipCode = zipCode;
this.street = street;
this.notes = notes;
this.user = user;
}
}
像往常一样,它包含 地址 数据库 table 的映射,还包含链接此 [=] 的 ManyToOne 关系103=]到上一个用户class:
@ManyToOne
@EqualsAndHashCode.Exclude // Needed by Lombock in "Many To One" relathionship to avoid error
@JoinColumn(name = "id", referencedColumnName = "id")
@JsonBackReference
private User user;
基本上它说 Address 的多个实例链接到 User.
的单个特定实例
为了完整起见,这只是我的存储库界面(目前它是空的,因为我只测试 提供的 save() 方法JpaRepository):
public interface UsersRepository extends JpaRepository<User, Integer> {
}
最后我创建了这个单元测试 class 以测试插入具有相关地址的新用户:
@SpringBootTest()
@ContextConfiguration(classes = GetUserWsApplication.class)
@TestMethodOrder(OrderAnnotation.class)
public class UserRepositoryTest {
@Autowired
private UsersRepository userRepository;
@Test
@Order(1)
public void testInsertUser() {
User user = new User("Mario", null, "Rossi", 'M', new Date(), "XXX", "xxx@gmail.com", "329123456", new Date());
userRepository.save(user);
Set<Address> addressesList = new HashSet<>();
addressesList.add(new Address("Italy", "RM", "00100", "Via XXX 123", "near YYY", user));
assertTrue(true);
}
}
问题是 运行 这个测试方法我在我的堆栈跟踪中获得以下错误消息:
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Repeated column in mapping for entity: com.easydefi.users.entity.Address column: id (should be mapped with insert="false" update="false")
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:421) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.3.12.jar:5.3.12]
... 84 common frames omitted
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.easydefi.users.entity.Address column: id (should be mapped with insert="false" update="false")
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:862) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:880) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:902) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:634) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.mapping.RootClass.validate(RootClass.java:267) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:354) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:298) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:468) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1259) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-5.3.12.jar:5.3.12]
... 88 common frames omitted
为什么会出现这个错误?我错过了什么?我该如何解决这个错误?
您似乎在 Address
中映射了同一列两次
@EqualsAndHashCode.Exclude // Needed by Lombock in "Many To One" relathionship to avoid error
@JoinColumn(name = "id", referencedColumnName = "id")
@JsonBackReference
private User user;
和
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
您可能想在第一个中说 user_id 但不能确定,因为我认为您为 table 创建粘贴了相同的 SQL 两次而不是地址一次。
编辑:
尝试在地址中的用户用户映射中使用 user_id 而不是 id,错误应该消失。
这是你的双重映射
@ManyToOne
@EqualsAndHashCode.Exclude // Needed by Lombock in "Many To One" relathionship to avoid error
@JoinColumn(name = "id", referencedColumnName = "id")
private User user;
应该是:
@ManyToOne
@EqualsAndHashCode.Exclude // Needed by Lombock in "Many To One" relathionship to avoid error
@JoinColumn(name = "fk_user_id", referencedColumnName = "id")
private User user;
您正在映射 id
两次(第一次出现是 @Id
列名称),根据您的 DDL,外键列应该是 fk_user_id
。
我正在使用 Spring Data JPA 开发 Spring 引导应用程序,我发现在实施 Hibernate 映射时出现以下问题。
基本上我首先在我的数据库上创建了 tables,然后我创建了映射这些 table 的实体 classes(在我的项目中,数据库 tables 是不是从实体自动生成的 classes).
我有这两个数据库 tables:
portal_user:这是主要的 table 包含代表门户用户的记录。
CREATE TABLE IF NOT EXISTS public.portal_user ( id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ), first_name character varying(50) COLLATE pg_catalog."default" NOT NULL, middle_name character varying(50) COLLATE pg_catalog."default", surname character varying(50) COLLATE pg_catalog."default" NOT NULL, sex "char" NOT NULL, birthdate date NOT NULL, tex_code character varying(50) COLLATE pg_catalog."default" NOT NULL, e_mail character varying(50) COLLATE pg_catalog."default" NOT NULL, contact_number character varying(50) COLLATE pg_catalog."default" NOT NULL, created_at date NOT NULL, CONSTRAINT user_pkey PRIMARY KEY (id) )
address:它包含代表以前用户地址的记录。每个用户可以有一个或多个地址。
CREATE TABLE IF NOT EXISTS public.address ( id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ), country character varying(50) COLLATE pg_catalog."default" NOT NULL, province character varying(50) COLLATE pg_catalog."default" NOT NULL, zip_code character varying(5) COLLATE pg_catalog."default" NOT NULL, street character varying(250) COLLATE pg_catalog."default" NOT NULL, notes character varying(250) COLLATE pg_catalog."default", fk_user_id bigint NOT NULL, CONSTRAINT address_pkey PRIMARY KEY (id), CONSTRAINT fk_user_id FOREIGN KEY (fk_user_id) REFERENCES public.portal_user (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION NOT VALID )
如您所见,每个用户可以拥有一个或多个地址,因此 portal_user 和 地址 之间的关系是 ONE TO MANY(因为一个用户可以有多个地址)。要实现此行为,address 包含 fk_user_id 字段,表示特定 portal_user 的 ID 记录。
好的,那么我将尝试使用 Hibernate 映射这两个 table 及其关系。
首先我创建了 User 实体 class:
@Entity
@Table(name = "portal_user")
@Data
public class User implements Serializable {
private static final long serialVersionUID = 5062673109048808267L;
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "middle_name")
private String middleName;
@Column(name = "surname")
private String surname;
@Column(name = "sex")
private char sex;
@Column(name = "birthdate")
private Date birthdate;
@Column(name = "tex_code")
private String taxCode;
@Column(name = "e_mail")
private String eMail;
@Column(name = "contact_number")
private String contactNumber;
@Temporal(TemporalType.DATE)
@Column(name = "created_at")
private Date createdAt;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
@JsonManagedReference
private Set<Address> addressesList = new HashSet<>();
public User(String firstName, String middleName, String surname, char sex, Date birthdate, String taxCode,
String eMail, String contactNumber, Date createdAt) {
super();
this.firstName = firstName;
this.middleName = middleName;
this.surname = surname;
this.sex = sex;
this.birthdate = birthdate;
this.taxCode = taxCode;
this.eMail = eMail;
this.contactNumber = contactNumber;
this.createdAt = createdAt;
}
}
如您所见,此 class 包含定义到 portal_user 数据库 table 和此 中的所有字段OneToMany 关系。基本上它说一个用户与多个地址相关:
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
@JsonManagedReference
private Set<Address> addressesList = new HashSet<>();
然后我创建了 Address 实体 class 映射我的数据库 address table,这个:
@Entity
@Table(name = "address")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address implements Serializable {
private static final long serialVersionUID = 6956974379644960088L;
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name = "country")
private String country;
@Column(name = "province")
private String province;
@Column(name = "zip_code")
private String zipCode;
@Column(name = "street")
private String street;
@Column(name = "notes")
private String notes;
//@Column(name = "fk_user_id")
//private int fkUserId;
@ManyToOne
@EqualsAndHashCode.Exclude // Needed by Lombock in "Many To One" relathionship to avoid error
@JoinColumn(name = "id", referencedColumnName = "id")
@JsonBackReference
private User user;
public Address(String country, String province, String zipCode, String street, String notes, User user) {
super();
this.country = country;
this.province = province;
this.zipCode = zipCode;
this.street = street;
this.notes = notes;
this.user = user;
}
}
像往常一样,它包含 地址 数据库 table 的映射,还包含链接此 [=] 的 ManyToOne 关系103=]到上一个用户class:
@ManyToOne
@EqualsAndHashCode.Exclude // Needed by Lombock in "Many To One" relathionship to avoid error
@JoinColumn(name = "id", referencedColumnName = "id")
@JsonBackReference
private User user;
基本上它说 Address 的多个实例链接到 User.
的单个特定实例为了完整起见,这只是我的存储库界面(目前它是空的,因为我只测试 提供的 save() 方法JpaRepository):
public interface UsersRepository extends JpaRepository<User, Integer> {
}
最后我创建了这个单元测试 class 以测试插入具有相关地址的新用户:
@SpringBootTest()
@ContextConfiguration(classes = GetUserWsApplication.class)
@TestMethodOrder(OrderAnnotation.class)
public class UserRepositoryTest {
@Autowired
private UsersRepository userRepository;
@Test
@Order(1)
public void testInsertUser() {
User user = new User("Mario", null, "Rossi", 'M', new Date(), "XXX", "xxx@gmail.com", "329123456", new Date());
userRepository.save(user);
Set<Address> addressesList = new HashSet<>();
addressesList.add(new Address("Italy", "RM", "00100", "Via XXX 123", "near YYY", user));
assertTrue(true);
}
}
问题是 运行 这个测试方法我在我的堆栈跟踪中获得以下错误消息:
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Repeated column in mapping for entity: com.easydefi.users.entity.Address column: id (should be mapped with insert="false" update="false")
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:421) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) ~[spring-beans-5.3.12.jar:5.3.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.3.12.jar:5.3.12]
... 84 common frames omitted
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.easydefi.users.entity.Address column: id (should be mapped with insert="false" update="false")
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:862) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:880) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:902) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:634) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.mapping.RootClass.validate(RootClass.java:267) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:354) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:298) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:468) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1259) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.3.12.jar:5.3.12]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-5.3.12.jar:5.3.12]
... 88 common frames omitted
为什么会出现这个错误?我错过了什么?我该如何解决这个错误?
您似乎在 Address
中映射了同一列两次 @EqualsAndHashCode.Exclude // Needed by Lombock in "Many To One" relathionship to avoid error
@JoinColumn(name = "id", referencedColumnName = "id")
@JsonBackReference
private User user;
和
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
您可能想在第一个中说 user_id 但不能确定,因为我认为您为 table 创建粘贴了相同的 SQL 两次而不是地址一次。
编辑:
尝试在地址中的用户用户映射中使用 user_id 而不是 id,错误应该消失。
这是你的双重映射
@ManyToOne
@EqualsAndHashCode.Exclude // Needed by Lombock in "Many To One" relathionship to avoid error
@JoinColumn(name = "id", referencedColumnName = "id")
private User user;
应该是:
@ManyToOne
@EqualsAndHashCode.Exclude // Needed by Lombock in "Many To One" relathionship to avoid error
@JoinColumn(name = "fk_user_id", referencedColumnName = "id")
private User user;
您正在映射 id
两次(第一次出现是 @Id
列名称),根据您的 DDL,外键列应该是 fk_user_id
。