java JPA 和泛型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11260856/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JPA and generics
提问by jaakko
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?
我想知道带有泛型的抽象类将如何处理 JPA?我的意思是该领域需要什么样的注释?
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> {
}
回答by Edmondo1984
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.
JPA 完全能够处理您的提议,因为泛型出现在抽象类级别,而对于您的具体类,它每个类只有一个值。事实上,根据您选择的 @InheritanceStrategy 并为此使用不同的机制,JPA 会将您的子类存储在一个或多个表中。
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:
您可以自己弄清楚为什么您的案例不是问题,推理 ORM 如何将这两个类保存在数据库中:
- 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.
- 您可以将 MyStringClass 和 MyIntegerClass 存储在同一个表中,添加一个鉴别器列,以便 ORM 在从数据库加载时知道应该调用哪个构造函数。
- 您可以将每个子类存储在更多表中。
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:
这样做的原因是,在编译时,由于类型擦除,T 被“擦除”。它在编译时用于验证签名和类型的正确性,但随后在 JVM 中变成了 java.lang.Object。如果你一直关注到现在,你应该能够理解以下内容:
- 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.
- 在您的情况下, AbstractMyClass 的每个具体子类都有一个类型 T ,它是为该类的所有实例定义的。虽然 T 信息未保留在 AbstractMyClass 中,但它在子类中保留且唯一。
- 在我发布的第二种情况下,MyGenericClass 的每个可能的具体实例都可能具有不同的 T 值,并且由于类型擦除,此信息不会保留。
*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.
*注意:JPA 无法处理第二种情况的事实是绝对合理的,如果您属于这种情况,您应该问自己有关您的设计的问题。泛型是设计灵活类的好工具,可以以类型安全的方式处理其他类,但类型安全是一种编程语言概念,与持久性无关。
Extra : you could use javap to see what really is erasure. Take off annotations from MyGenericClass and compile it.
额外:您可以使用 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);
}
回答by Raymond
We can. if the T
implements Serializable
我们可以。如果T
实施Serializable
@Entity
public class IgsSubject extends BasicObject implements Serializable{
private static final long serialVersionUID = -5387429446192609471L;
@MappedSuperclass
public class IgsBasicLog<T> extends BasicObject {
@ManyToOne
@JoinColumn(name = "ITEM_ID")
private T item;
@Entity
public class IgsLogA extends IgsBasicLog<IgsSubject> implements Serializable {
private static final long serialVersionUID = -8207430344929724212L;
}