英文:
'mappedBy reference an unknown target entity property' when properties with the same name exist in both parent and child entities
问题
以下是翻译好的内容:
当我使用Spring Boot v1.5.3和Hibernate继承时,在父实体和子实体中存在相同名称的属性时,会出现AnnotationException: mappedBy reference an unknown target entity property
的错误。
例如:
Apple => RedApple
=> GreenApple
=> etc.
Tree => RedAppleTree
=> GreenAppleTree
=> etc.
// Tree.java
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@EqualsAndHashCode(exclude = {"apples"})
@DiscriminatorColumn(name = "colour")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Tree {
@Id
@GeneratedValue
private Long id;
}
// RedAppleTree.java
@Entity
@Table(name = "tree")
@DiscriminatorValue("RED")
public class RedAppleTree extends Tree {
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "tree")
private List<RedApple> apples;
}
// Apple.java
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@DiscriminatorColumn(name = "colour")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Apple {
@Id
@GeneratedValue
private Long id;
@Enumerated(EnumType.STRING)
@Column(insertable = false, updatable = false)
private Colour colour;
@JoinColumn(insertable = false, updatable = false)
@ManyToOne
private Tree tree;
}
// RedApple.java
@Entity
@Table(name = "apple")
@DiscriminatorValue("RED")
public class RedApple extends Apple {
@JoinColumn(insertable = false, updatable = false)
@ManyToOne
private RedAppleTree tree;
}
// Colour.java
public enum Colour {
RED,
GREEN,
}
Apple.tree
和RedApple.tree
同时存在。在父类Apple
中,类型是Tree
;在子类RedApple
中,类型是RedAppleTree
。
现在当项目运行时,会出现以下错误:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.example.demo.dao.RedApple.tree in com.example.demo.dao.RedAppleTree.apples
...
Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.example.demo.dao.RedApple.tree in com.example.demo.dao.RedAppleTree.apples
...
现在我可以将其中一个属性重命名以解决此问题,但在我实际工作的项目中,这将导致更多的更改。
是否有可能保持属性名称不变?
英文:
I'm on Spring Boot v1.5.3 and when I use Hibernate inheritance, AnnotationException: mappedBy reference an unknown target entity property
occurs when there are properties with the same name in both parent and child entities.
For example:
Apple => RedApple
=> GreenApple
=> etc.
Tree => RedAppleTree
=> GreenAppleTree
=> etc.
// Tree.java
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@EqualsAndHashCode(exclude = {"apples"})
@DiscriminatorColumn(name = "colour")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Tree {
@Id
@GeneratedValue
private Long id;
}
// RedAppleTree.java
@Entity
@Table(name = "tree")
@DiscriminatorValue("RED")
public class RedAppleTree extends Tree {
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "tree")
private List<RedApple> apples;
}
// Apple.java
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@DiscriminatorColumn(name = "colour")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Apple {
@Id
@GeneratedValue
private Long id;
@Enumerated(EnumType.STRING)
@Column(insertable = false, updatable = false)
private Colour colour;
@JoinColumn(insertable = false, updatable = false)
@ManyToOne
private Tree tree;
}
// RedApple.java
@Entity
@Table(name = "apple")
@DiscriminatorValue("RED")
public class RedApple extends Apple {
@JoinColumn(insertable = false, updatable = false)
@ManyToOne
private RedAppleTree tree;
}
// Colour.java
public enum Colour {
RED,
GREEN,
}
Apple.tree
and RedApple.tree
exist at the same time. In parent Apple
the type is Tree
; in child RedApple
it's RedAppleTree
.
Now when the project runs, I get:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.example.demo.dao.RedApple.tree in com.example.demo.dao.RedAppleTree.apples
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean (AbstractAutowireCapableBeanFactory.java:1628)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean (AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean (AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject (AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton (DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean (AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean (AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean (AbstractApplicationContext.java:1081)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization (AbstractApplicationContext.java:856)
at org.springframework.context.support.AbstractApplicationContext.refresh (AbstractApplicationContext.java:542)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh (EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh (SpringApplication.java:737)
at org.springframework.boot.SpringApplication.refreshContext (SpringApplication.java:370)
at org.springframework.boot.SpringApplication.run (SpringApplication.java:314)
at org.springframework.boot.SpringApplication.run (SpringApplication.java:1162)
at org.springframework.boot.SpringApplication.run (SpringApplication.java:1151)
at com.example.demo.DemoApplication.main (DemoApplication.java:13)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke (Method.java:566)
at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run (AbstractRunMojo.java:527)
at java.lang.Thread.run (Thread.java:834)
Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.example.demo.dao.RedApple.tree in com.example.demo.dao.RedAppleTree.apples
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass (CollectionBinder.java:769)
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass (CollectionBinder.java:719)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass (CollectionSecondPass.java:54)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses (InFlightMetadataCollectorImpl.java:1655)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses (InFlightMetadataCollectorImpl.java:1623)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete (MetadataBuildingProcess.java:278)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata (EntityManagerFactoryBuilderImpl.java:847)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build (EntityManagerFactoryBuilderImpl.java:874)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory (SpringHibernateJpaPersistenceProvider.java:60)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory (LocalContainerEntityManagerFactoryBean.java:353)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory (AbstractEntityManagerFactoryBean.java:370)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet (AbstractEntityManagerFactoryBean.java:359)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods (AbstractAutowireCapableBeanFactory.java:1687)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean (AbstractAutowireCapableBeanFactory.java:1624)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean (AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean (AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject (AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton (DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean (AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean (AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean (AbstractApplicationContext.java:1081)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization (AbstractApplicationContext.java:856)
at org.springframework.context.support.AbstractApplicationContext.refresh (AbstractApplicationContext.java:542)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh (EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh (SpringApplication.java:737)
at org.springframework.boot.SpringApplication.refreshContext (SpringApplication.java:370)
at org.springframework.boot.SpringApplication.run (SpringApplication.java:314)
at org.springframework.boot.SpringApplication.run (SpringApplication.java:1162)
at org.springframework.boot.SpringApplication.run (SpringApplication.java:1151)
at com.example.demo.DemoApplication.main (DemoApplication.java:13)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke (Method.java:566)
at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run (AbstractRunMojo.java:527)
at java.lang.Thread.run (Thread.java:834)
Now I can rename one of the properties to work around this problem but in the actual project I'm working on it'd lead to more changes.
Is it possible to keep the property name untouched?
答案1
得分: 1
这在您的超类和子类中都重复使用了 "tree" 属性,这是一个问题。我相信这里的示例将实现您想要的效果。
Tree.java
@Entity
@Table(name = "tree")
@DiscriminatorColumn(name = "colour")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Tree<APPLE extends Apple> {
@Id
@GeneratedValue
private Long id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "tree", targetEntity = Apple.class)
private Set<APPLE> apples = Sets.newHashSet();
//... getters & setters
}
Apple.java
@Table(name = "apple")
@Entity
@DiscriminatorColumn(name = "colour")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Apple<TREE extends Tree> {
@Id
@GeneratedValue
private Long id;
@JoinColumn(name = "tree_id")
@ManyToOne(targetEntity = Tree.class)
private TREE tree;
}
RedAppleTree.java
@Entity
@Table(name = "tree")
@DiscriminatorColumn(name = "colour")
@DiscriminatorValue("RED")
public class RedAppleTree extends Tree<RedApple> {
}
RedApple.java
@Entity
@Table(name = "apple")
@DiscriminatorColumn(name = "colour")
@DiscriminatorValue("RED")
public class RedApple extends Apple<RedAppleTree> {
}
这将创建以下数据库表格:
create table tree (
colour varchar(31) not null,
id bigint generated by default as identity (start with 1),
primary key (id)
);
create table apple (
colour varchar(31) not null,
id bigint generated by default as identity (start with 1),
tree_id bigint,
primary key (id)
)
然后,当我运行以下代码时:
@Test
public void test() {
RedAppleTree tree = new RedAppleTree();
session.persist(tree);
RedApple apple = new RedApple();
apple.setTree(tree);
session.persist(apple);
tree.getApples().add(apple);
session.flush();
session.clear();
tree = session.get(RedAppleTree.class, tree.getId());
System.err.println(session.createCriteria(RedAppleTree.class).list());
}
这将产生以下SQL(在启用了 hibernate-sql-logging 的情况下运行):
Hibernate:
insert
into
tree
(id, version, colour)
values
(default, ?, 'RED')
Hibernate:
insert
into
apple
(id, version, tree_id, colour)
values
(default, ?, ?, 'RED')
Hibernate:
select
redappletr0_.id as id2_409_0_,
redappletr0_.version as version3_409_0_
from
tree redappletr0_
where
redappletr0_.id=?
and redappletr0_.colour='RED'
我认为这应该解决您的基本问题。
英文:
It is a problem to duplicate your "tree" property in both your superclass and your subclass. I believe that this example here will do what you want.
Tree.java
@Entity
@Table(name = "tree")
@DiscriminatorColumn(name = "colour")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Tree<APPLE extends Apple> {
@Id
@GeneratedValue
private Long id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "tree", targetEntity = Apple.class)
private Set<APPLE> apples = Sets.newHashSet();
//... getters & setters
}
Apple.java
@Table(name = "apple")
@Entity
@DiscriminatorColumn(name = "colour")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Apple<TREE extends Tree> {
@Id
@GeneratedValue
private Long id;
@JoinColumn(name = "tree_id")
@ManyToOne(targetEntity = Tree.class)
private TREE tree;
}
RedAppleTree.java
@Entity
@Table(name = "tree")
@DiscriminatorColumn(name = "colour")
@DiscriminatorValue("RED")
public class RedAppleTree extends Tree<RedApple> {
}
RedApple.java
@Entity
@Table(name = "apple")
@DiscriminatorColumn(name = "colour")
@DiscriminatorValue("RED")
public class RedApple extends Apple<RedAppleTree> {
}
This creates the following DB tables
create table tree (
colour varchar(31) not null,
id bigint generated by default as identity (start with 1),
primary key (id)
);
create table apple (
colour varchar(31) not null,
id bigint generated by default as identity (start with 1),
tree_id bigint,
primary key (id)
)
Then, when I run the following code
@Test
public void test() {
RedAppleTree tree = new RedAppleTree();
session.persist(tree);
GreenAppleTree greenTree = new GreenAppleTree();
session.persist(greenTree);
RedApple apple = new RedApple();
apple.setTree(tree);
session.persist(apple);
tree.getApples().add(apple);
session.flush();
session.clear();
tree = session.get(RedAppleTree.class, tree.getId());
System.err.println(session.createCriteria(RedAppleTree.class).list());
}
This results in the following SQL (ran with hibernate-sql-logging enabled)
Hibernate:
insert
into
tree
(id, version, colour)
values
(default, ?, 'RED')
Hibernate:
insert
into
tree
(id, version, colour)
values
(default, ?, 'GREEN')
Hibernate:
insert
into
apple
(id, version, tree_id, colour)
values
(default, ?, ?, 'RED')
Hibernate:
select
redappletr0_.id as id2_409_0_,
redappletr0_.version as version3_409_0_
from
tree redappletr0_
where
redappletr0_.id=?
and redappletr0_.colour='RED'
Hibernate:
select
this_.id as id2_409_0_,
this_.version as version3_409_0_
from
tree this_
where
this_.colour='RED'
I believe that this ought to solve your basic problem.
答案2
得分: 0
事实上,我从未遇到过类似的问题,逻辑上,一个很好的做法是将属性的名称更改为不同的实体,以区分每个实体所指的内容,编译器会指示您在哪里进行更改。
您可以尝试在关系中指示子类,如下所示:
mappedBy = "tree", targetEntity = RedAppleTree.class
但我再次强调,最好的选择是更改属性的名称,即使这需要更多的工作。
英文:
The truth is that I have never encountered a similar problem, the logical thing, and a good practice would be to change the name of the property to differentiate which entity each one refers to, the compiler will tell you where to change it.
You could try indicating the child class in the relation as follows:
mappedBy = "tree", targetEntity = RedAppleTree.class
But I reiterate, the best option would be to change the name of the property, even if it involves more work.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论