【问题标题】:DuplicateMappingException while converting Inheritence strategy from InheritanceType.JOINED to InheritanceType.SINGLE_TABLE将继承策略从 InheritanceType.JOINED 转换为 InheritanceType.SINGLE_TABLE 时出现 DuplicateMappingException
【发布时间】:2020-07-09 07:27:15
【问题描述】:

问题:我有一个遗留应用程序,其中包含一个抽象超类(比如说Task)和50 多个称为SubTask1 的子类等等。此外,这些子类具有多个具有相同名称的字段,例如filenameuser 等。此外,这些子类与一个类具有不同的@ManyToOne 关系(比如说Property)。

现在,作为 ORM 工具,我们使用 hibernate,继承策略为 JOINED。现在,这些实体的查询性能非常糟糕。因此,为了提高性能,我尝试将继承策略更改为 SINGLE_TABLE 并让 hibernate 生成架构。

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
abstract public class Task {
    public String type;

    //Getters and setters
}

@Entity 
public class SubTask1 extends Task {
    public subTask1Field;
    public String user;
    public string filename;
    @ManyToOne(optional = false)
    public Property host;
    //Getters and setters

}

@Entity 
public class SubTask2 extends Task {
    public subTask2Field;

    public String user;
    public string filename;
    @ManyToOne(optional = false)
    public Property host;
    //Getters and setters

}

@Entity
public class Property {
    @Unique
    @Required
    public String name;

    @Required
    public String value;    
}

问题:在应用程序启动期间,我遇到异常。

2020-07-09 12:18:26,665 ERROR --- [                     main] play                           :   Can't start in PROD mode with errors
javax.persistence.PersistenceException: Unable to build EntityManagerFactory
        at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:925)
        at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:900)
        at play.db.jpa.JPAPlugin.onApplicationStart(JPAPlugin.java:204)
        at play.plugins.PluginCollection.onApplicationStart(PluginCollection.java:616)
        at play.Play.start(Play.java:538)
        at play.Play.init(Play.java:309)
        at play.server.Server.main(Server.java:160)
Caused by: org.hibernate.DuplicateMappingException:  Table [Task] contains logical column name [fileName] referenced by multiple physical column names: [`filename`], [`fileName`]
        at org.hibernate.cfg.Configuration$MappingsImpl$TableColumnNameBinding.bindLogicalToPhysical(Configuration.java:3021)
        at org.hibernate.cfg.Configuration$MappingsImpl$TableColumnNameBinding.addBinding(Configuration.java:3008)
        at org.hibernate.cfg.Configuration$MappingsImpl.addColumnBinding(Configuration.java:3053)
        at org.hibernate.cfg.Ejb3Column.addColumnBinding(Ejb3Column.java:330)
        at org.hibernate.cfg.Ejb3Column.linkWithValue(Ejb3Column.java:322)
        at org.hibernate.cfg.annotations.SimpleValueBinder.linkWithValue(SimpleValueBinder.java:361)
        at org.hibernate.cfg.annotations.SimpleValueBinder.make(SimpleValueBinder.java:336)
        at org.hibernate.cfg.annotations.PropertyBinder.makePropertyAndValue(PropertyBinder.java:193)
        at org.hibernate.cfg.annotations.PropertyBinder.makePropertyValueAndBind(PropertyBinder.java:205)
        at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2166)
        at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:895)
        at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:728)
        at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3625)
        at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3579)
        at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1381)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1786)
        at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:96)
        at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:918)
        ... 6 common frames omitted
Exception in thread "main" play.exceptions.UnexpectedException: Unexpected Error
        at play.Play.start(Play.java:568)
        at play.Play.init(Play.java:309)
        at play.server.Server.main(Server.java:160)
Caused by: javax.persistence.PersistenceException: Unable to build EntityManagerFactory
        at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:925)
        at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:900)
        at play.db.jpa.JPAPlugin.onApplicationStart(JPAPlugin.java:204)
        at play.plugins.PluginCollection.onApplicationStart(PluginCollection.java:616)
        at play.Play.start(Play.java:538)
        ... 2 more
Caused by: org.hibernate.DuplicateMappingException:  Table [Task] contains logical column name [fileName] referenced by multiple physical column names: [`filename`], [`fileName`]
        at org.hibernate.cfg.Configuration$MappingsImpl$TableColumnNameBinding.bindLogicalToPhysical(Configuration.java:3021)
        at org.hibernate.cfg.Configuration$MappingsImpl$TableColumnNameBinding.addBinding(Configuration.java:3008)
        at org.hibernate.cfg.Configuration$MappingsImpl.addColumnBinding(Configuration.java:3053)
        at org.hibernate.cfg.Ejb3Column.addColumnBinding(Ejb3Column.java:330)
        at org.hibernate.cfg.Ejb3Column.linkWithValue(Ejb3Column.java:322)
        at org.hibernate.cfg.annotations.SimpleValueBinder.linkWithValue(SimpleValueBinder.java:361)
        at org.hibernate.cfg.annotations.SimpleValueBinder.make(SimpleValueBinder.java:336)
        at org.hibernate.cfg.annotations.PropertyBinder.makePropertyAndValue(PropertyBinder.java:193)
        at org.hibernate.cfg.annotations.PropertyBinder.makePropertyValueAndBind(PropertyBinder.java:205)
        at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2166)
        at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:895)
        at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:728)
        at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3625)
        at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3579)
        at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1381)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1786)
        at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:96)
        at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:918)
        ... 6 more

问题:

  1. 是否甚至可以在不更改我的实体类的情况下转换这样的继承策略?如果是,您会建议对此进行哪些更改?
  2. 这里有没有其他方法可以提高查询性能?每当我尝试获取Task 实体时,它都会在所有SubTask 表上创建一个连接,每个SubTask 表都与Property 表连接。

【问题讨论】:

  • 您正在使用继承,为什么还要复制字段?即使加入也没有意义。 JOINED 和 SINGLE_TABLE 的性能没有变化。您必须有另一个性能问题。你检查生成的 SQL 了吗?
  • 是的,我同意重复字段的问题。它不是设计它的理想方式。但由于它是一个遗留应用程序,我对此无能为力。此外,这些类很大,我什至不能冒险巩固超类中的共同领域。是的,我已经看到了生成的 SQL。它们是 600 多行 sql 生成的,包含所有表之间的连接。我的感觉是,如果我更改继承类型,所有这些连接都将不存在。
  • 是的,但所有数据都将位于同一个数据库表中。而且您说您无法更改旧版应用程序。使用 SINGLE_TABLE 您将不得不更改数据库模型
  • 是的,我愿意更改数据库。不会有别的办法了。我希望对 Java 代码进行最小的更改。到目前为止,我只更改了一行,即更改超类的继承类型。
  • 所以答案是:只要你的类中有重复的属性,就没有办法让它工作

标签: hibernate jpa


【解决方案1】:

问题是 [filename], [fileName] 你用不同的情况写了相同的属性。

【讨论】:

  • 谢谢西蒙。幸运的是,这只是一个有这 1 个冲突的子类。
猜你喜欢
  • 2012-04-17
  • 2021-11-20
  • 2011-11-15
  • 1970-01-01
  • 2019-04-28
  • 1970-01-01
  • 2018-07-02
  • 2014-07-04
  • 2019-01-06
相关资源
最近更新 更多