JPA和泛型 [英] JPA and generics

查看:101
本文介绍了JPA和泛型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



考虑这些:

  @MappedSuperclass 
public abstract class AbstractMyClass< T> {
//字符串和整数怎么样?我需要某种@LOB吗?
私人T字段;

public T getField(){
return field;
}

public void setField(T field){
this.field = field;
}
}

然后这些

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

@Entity
@Table(name =Integer)
public class MyIntegerClass extends AbstractMyClass< Integer> {
}


解决方案

JPA完全可以处理你的提议,因为泛型出现在抽象类层次上,对于具体类,它每个类只有一个值。实际上,根据您选择的@InheritanceStrategy,JPA会将您的子类存储在一个或多个表中,并为此使用不同的机制。



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


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


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

$ pre code $ @Entity
@Table(name =MyGenericClass)
public class MyGenericClass< T> {
private T t;
public MyGenericClass(T t){
this.t = t;






原因是,在编译时,由于类型擦除,T被擦除。它在编译时用于验证签名和类型的正确性,但是随后它会在JVM中变成java.lang.Object。如果您追踪至今,您应该能够理解以下内容:


  • 在您的情况中,AbstractMyClass的每个具体子类都有一个类型T这是为类的所有实例定义的。虽然T信息未保留到AbstractMyClass中,但它在子类中保留且唯一。

  • 在我发布的第二种情况下,MyGenericClass的每个可能的具体实例都可能具有T的不同值,并且由于类型擦除,此信息不会被保留。 $ b


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



额外:你可以使用javap来查看真正的擦除。从MyGenericClass中取出注释并编译它。

  G:\> javac MyGenericClass.java 

G:\> javap - p MyGenericClass
从MyGenericClass.java编译
public class MyGenericClass extends java.lang.Object {
private java.lang.Object t;
public MyGenericClass(java.lang.Object);
}


I'm wondering how an abstract class with generics would handle with JPA? I mean what kind of annotations do I need for the field?

Consider these:

@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;
  }
}

And then these

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

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

解决方案

JPA is perfectly able to handle your proposed, because the generic appears at the abstract class level and for your concrete classes it has exactly a single value per class. In fact, JPA will store your subclasses in one or more table, according to the @InheritanceStrategy you have chosen and uses different mechanism for that.

You can figure out yourself why your case is not a problem, reasoning about how an ORM could save the two classes on a DB:

  • You can store MyStringClass and MyIntegerClass in the same table, adding a Discriminator column so that the ORM, when it loads from the DB, know which constructor should be called.
  • You can store every subclass in more table.

What is not possible, on the other side, is to define a generic

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

The reason for this is that, at compile time, the T is "erased" because of type erasure. It is used at compile time to verify signatures and correctness of types, but then it is turned into a java.lang.Object inside the JVM. If you follow until now, you should be able to understand the following:

  • In your case, every concrete subclass of AbstractMyClass has a type T which is defined for all instances of the class. While the T information is not retained into the AbstractMyClass, it is retained and unique inside the subclasses.
  • In the second case I posted, each possible concrete instance of MyGenericClass could have a possible different value for T, and because of type erasure this information is not retained.

*Note: the fact that the second case cannot be handled by JPA is absolutely reasonable and if you fall in that case you should ask yourself questions about your design. Generics are a great tool to design flexible classes which can handle other classes in a type-safe manner, but type-safe is a programming language concept which has nothing to do with persistance.


Extra : you could use javap to see what really is erasure. Take off annotations from MyGenericClass and compile it.

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);
}

这篇关于JPA和泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆