'mappedBy reference an unknown target entity property' when properties with the same name exist in both parent and child entities

huangapple go评论146阅读模式
英文:

'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.treeRedApple.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 =&gt; RedApple
      =&gt; GreenApple
      =&gt; etc.
Tree  =&gt; RedAppleTree
      =&gt; GreenAppleTree
      =&gt; etc.
// Tree.java

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@EqualsAndHashCode(exclude = {&quot;apples&quot;})
@DiscriminatorColumn(name = &quot;colour&quot;)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Tree {
    @Id
    @GeneratedValue
    private Long id;
}
// RedAppleTree.java

@Entity
@Table(name = &quot;tree&quot;)
@DiscriminatorValue(&quot;RED&quot;)
public class RedAppleTree extends Tree {
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = &quot;tree&quot;)
    private List&lt;RedApple&gt; apples;
}
// Apple.java

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@DiscriminatorColumn(name = &quot;colour&quot;)
@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 = &quot;apple&quot;)
@DiscriminatorValue(&quot;RED&quot;)
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 &#39;entityManagerFactory&#39; 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 = &quot;tree&quot;)
@DiscriminatorColumn(name = &quot;colour&quot;)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Tree&lt;APPLE extends Apple&gt; {

    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = &quot;tree&quot;, targetEntity = Apple.class)
    private Set&lt;APPLE&gt; apples = Sets.newHashSet();

    //... getters &amp; setters
}

Apple.java

@Table(name = &quot;apple&quot;)
@Entity
@DiscriminatorColumn(name = &quot;colour&quot;)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Apple&lt;TREE extends Tree&gt; {

    @Id
    @GeneratedValue
    private Long id;

    @JoinColumn(name = &quot;tree_id&quot;)
    @ManyToOne(targetEntity = Tree.class)
    private TREE tree;

}

RedAppleTree.java

@Entity
@Table(name = &quot;tree&quot;)
@DiscriminatorColumn(name = &quot;colour&quot;)
@DiscriminatorValue(&quot;RED&quot;)
public class RedAppleTree extends Tree&lt;RedApple&gt; {
}

RedApple.java

@Entity
@Table(name = &quot;apple&quot;)
@DiscriminatorColumn(name = &quot;colour&quot;)
@DiscriminatorValue(&quot;RED&quot;)
public class RedApple extends Apple&lt;RedAppleTree&gt; {
}

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, ?, &#39;RED&#39;)
Hibernate: 
insert 
into
    tree
    (id, version, colour) 
values
    (default, ?, &#39;GREEN&#39;)
Hibernate: 
insert 
into
    apple
    (id, version, tree_id, colour) 
values
    (default, ?, ?, &#39;RED&#39;)
Hibernate: 
select
    redappletr0_.id as id2_409_0_,
    redappletr0_.version as version3_409_0_ 
from
    tree redappletr0_ 
where
    redappletr0_.id=? 
    and redappletr0_.colour=&#39;RED&#39;
Hibernate: 
select
    this_.id as id2_409_0_,
    this_.version as version3_409_0_ 
from
    tree this_ 
where
    this_.colour=&#39;RED&#39;

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 = &quot;tree&quot;, targetEntity = RedAppleTree.class

But I reiterate, the best option would be to change the name of the property, even if it involves more work.

huangapple
  • 本文由 发表于 2020年10月14日 13:29:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/64347162.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定