JPA和泛型

jaa*_*kko 9 java generics jpa

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

考虑这些:

@MappedSuperclass
public abstract class AbstractMyClass<T> {
  // 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后是这些

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

@Entity
@Table(name = "Integer")
public class MyIntegerClass extends AbstractMyClass<Integer> {
}
Run Code Online (Sandbox Code Playgroud)

Edm*_*984 7

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

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

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

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

@Entity
@Table(name = "MyGenericClass")
public class MyGenericClass<T> {
    private T t;
    public MyGenericClass(T t) {
       this.t=t;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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


额外:您可以使用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);
}
Run Code Online (Sandbox Code Playgroud)