JPA和generics

我想知道带有generics的抽象类如何处理JPA? 我的意思是我需要什么样的注释?

考虑这些:

@MappedSuperclass public abstract class AbstractMyClass { // What about Strings and Integers? Do I need some kind of @LOB? private T field; public T getField() { return field; } public void setField(T field) { this.field = field; } } 

然后是这些

 @Entity @Table(name = "String") public class MyStringClass extends AbstractMyClass { } @Entity @Table(name = "Integer") public class MyIntegerClass extends AbstractMyClass { } 

JPA完全能够处理您的建议,因为generics出现在抽象类级别,对于您的具体类,它每个类只有一个值。 实际上,根据您选择的@InheritanceStrategy,JPA会将您的子类存储在一个或多个表中,并使用不同的机制。

你可以弄清楚为什么你的案例不成问题,推理ORM如何在DB上保存这两个类:

  • 您可以将MyStringClass和MyIntegerClass存储在同一个表中,添加一个Discriminator列,以便ORM在从DB加载时知道应该调用哪个构造函数。
  • 您可以将每个子类存储在更多表中。

另一方面,不可能的是定义一个通用的

 @Entity @Table(name = "MyGenericClass") public class MyGenericClass { private T t; public MyGenericClass(T t) { this.t=t; } } 

这样做的原因是,在编译时,由于类型擦除,T被“擦除”。 它在编译时用于validation类型的签名和正确性,但随后它变成了JVM中的java.lang.Object。 如果您遵循到现在,您应该能够理解以下内容:

  • 在您的情况下,AbstractMyClass的每个具体子类都有一个类型T,它是为类的所有实例定义的。 虽然T信息不会保留在AbstractMyClass中,但它在子类中保留并且是唯一的。
  • 在我发布的第二种情况中,MyGenericClass的每个可能的具体实例可能具有可能的T的不同值,并且由于类型擦除,因此不保留该信息。

*注意:第二种情况不能由JPA处理的事实是绝对合理的,如果你属于这种情况,你应该问自己有关你的设计的问题。 generics是设计灵活类的一个很好的工具,它可以以类型安全的方式处理其他类,但类型安全是一种与持久性无关的编程语言概念。


额外:您可以使用javap来查看真正的擦除内容。 从MyGenericClass中取出注释并进行编译。

 G:\>javac MyGenericClass.java G:\>javap -p MyGenericClass Compiled from "MyGenericClass.java" public class MyGenericClass extends java.lang.Object{ private java.lang.Object t; public MyGenericClass(java.lang.Object); } 

我们可以。 如果T实现Serializable

 @Entity public class IgsSubject extends BasicObject implements Serializable{ private static final long serialVersionUID = -5387429446192609471L; @MappedSuperclass public class IgsBasicLog extends BasicObject { @ManyToOne @JoinColumn(name = "ITEM_ID") private T item; @Entity public class IgsLogA extends IgsBasicLog implements Serializable { private static final long serialVersionUID = -8207430344929724212L; }