【问题标题】:Mapping of generic classes in HibernateHibernate 中泛型类的映射
【发布时间】:2014-04-15 09:25:48
【问题描述】:

我在 Java Hibernate 项目中有以下类:

@Entitiy
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ClassA<T extends ClassB>{

    @OneToOne
    @JoinColumn(name = "mycolumn_id")
    private T instance;

[...]

}


@Entitiy
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class ClassB{

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Integer id;

[...]

}

当我尝试创建/保存 ClassA 的实例(具有继承 ClassB 的类的实例)时,出现以下异常:

org.hibernate.AnnotationException: Property ClassA.instance has an unbound type and no explicit target entity. Resolve this Generic usage issue or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type

我无法在 ClassA 中将显式目标设置为“T 实例”,因为 ClassB 是抽象的并且文字“T.class”无效。但是通用用法是必要的,因为我必须在 ClassA 中保存许多不同类型的 ClassB。

我该如何解决这个问题?

【问题讨论】:

  • 为什么不能使用targetEntity=ClassB.class?仅仅是因为 ClassB 是抽象的吗?你可以让 ClassB 具体化,并防止使用受保护的构造函数直接实例化吗?
  • 我可以使用“targetEntity=ClassB.class”,但这会让我在运行时出现“无法实例化 ClassB”的异常。 Hibernate 尝试实例化 ClassB 而不是具体的类,这有点令人困惑。所以如果我用受保护的构造函数尝试它没有区别。
  • 我必须纠正我。 ClassB 的抽象构造函数不会导致异常。但这并不能解决我的问题,因为它会创建一个 ClassB 而不是具体类的条目。
  • 在您的情况下,hibernate 如何创建外键?我认为你不能在休眠中进行“动态”映射(如果我错了,请纠正我)。也许如果您将 ClassB 继承设置为 SingleTable,那么休眠将知道 ClassA 与哪个表相关并为其创建外键。

标签: java hibernate generics


【解决方案1】:

经过大量测试,试图让 Java 参数化与抽象父表(单表继承)和抽象子表(每类一个表继承)一起工作,我放弃了。

这可能是可能的,但是当 Hibernate 尝试将抽象(参数化)类实例化为实体时,您经常会遇到问题。

我建议使用 JPA 继承重写它,将参数化的东西下移到扩展类中。这样您就可以从数据库中获取相同的多态性。

@MappedSuperclass
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "CLASS_TYPE", discriminatorType = DiscriminatorType.STRING)
public abstract class ClassA {

  [...]

}

扩展 B:

@Entity
@DiscriminatorValue=("B")
public class ClassB extends ClassA {
  @OneToOne
  @JoinColumn(name = "mycolumn_id")
  private Integer instance;

  [...]
}

扩展 C:

@Entity
@DiscriminatorValue=("C")
public class ClassC extends ClassA {
  @OneToOne
  @JoinColumn(name = "mycolumn_id")
  private String instance;

  [...]
}

【讨论】:

    【解决方案2】:

    此错误来自 hibernate 尝试从抽象类(指定为“抽象”或使用 Java 参数)创建实体。

    您需要创建一个不是实体的抽象基类,然后将其扩展为特定类型。您的子类型可以在表中添加可为空的列,和/或指定参数。

    @MappedSuperclass
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name = "TRACK_TYPE", discriminatorType = DiscriminatorType.STRING)
    public abstract class ClassA<T extends ClassB>{
    
        @OneToOne
        @JoinColumn(name = "mycolumn_id")
        private T instance;
    
    [...]
    
    }
    

    您还需要确定 ClassB 是扩展 ClassA 还是相关表。您不能让 B 扩展 A,而是使用不同的继承类型。 假设单表:

    @Entity
    @DiscriminatorValue=("B")
    public class ClassB extends ClassA<Integer>{
    
      [...]
    
    }
    

    【讨论】:

    • 这会给出警告:WARN org.hibernate.cfg.AnnotationBinder - HHH000503: A class should not be annotated with both @Inheritance and @MappedSuperclass. @Inheritance will be ignored for: ...
    • 是的,它现在确实给出了警告......我刚刚注意到我的项目中有类似的警告。我怀疑自从这篇文章以来,Hibernate 已经改变了一些东西。有机会会更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多