java Hibernate 继承和具有相同类的多个表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6872828/
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
Hibernate inheritance and multiple tables with same class
提问by Andraz
I'm pretty new to Hibernate. In my situation I have a concrete table with records containing join IDs to a multitude of other tables - all with the same structure. What I'd like to achieve is get something like
我对 Hibernate 很陌生。在我的情况下,我有一个具体的表,其中包含与许多其他表的连接 ID 的记录 - 所有表都具有相同的结构。我想实现的是得到类似的东西
SELECT *
FROM main_records mr, ref1 r1, ref2 r2
WHERE r1.id = mr.id_ref1
AND r2.id = mr.id_ref2;
The main idea would be to reuse the class for all the join references.
主要思想是为所有连接引用重用该类。
SQL
查询语句
CREATE TABLE main_records
(
id integer NOT NULL,
id_ref1 integer NOT NULL,
id_ref2 integer NOT NULL
)
CREATE TABLE ref1
(
id integer NOT NULL,
value character varying
)
CREATE TABLE ref2
(
id integer NOT NULL,
value character varying
)
I've setup the base POJO classes
我已经设置了基本的 POJO 类
JAVA classes
JAVA课程
public class MainRecord {
private Integer id;
private Ref ref1;
private Ref ref2;
...
// getters and setters
}
public class Ref {
private Integer id;
private String value;
...
// getters and setters
}
My idea is to define the Hibernate mappings in following manner:
我的想法是按以下方式定义 Hibernate 映射:
Define an abstract super class
定义抽象超类
<hibernate-mapping package="test">
<class abstract="true" name="Ref">
<id name="id" type="java.lang.Integer" column="ID">
<generator class="native" />
</id>
<property name="value" type="java.lang.String" column="VALUE" />
</class>
</hibernate-mapping>
Map main entity, extend the super class but use individual tables
映射主实体,扩展超类但使用单独的表
<hibernate-mapping package="test">
<union-subclass name="Ref1" table="REF1" extends="Ref" />
<union-subclass name="Ref2" table="REF2" extends="Ref" />
<class name="MainRecord" table="MAIN_RECORDS">
<id name="id" column="ID" type="java.lang.Integer" />
<many-to-one name="ref1" class="Ref1" column="ID_REF1" fetch="join" unique="true" />
<many-to-one name="ref2" class="Ref2" column="ID_REF2" fetch="join" unique="true" />
</union-subclass>
</class>
</hibernate-mapping>
I do manually include mapping files in the configuration, loading seems ok but then an error occurs, without any detaild explanation:
我在配置中手动包含映射文件,加载似乎没问题但随后发生错误,没有任何详细说明:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.apache.cxf.transport.servlet.ServletTransportFactory' defined in class path resource [META-INF/cxf/cxf-servlet.xml]: Error setting property values;
nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (2) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'bus' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/spring/database.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Unable to instantiate default tuplizer [org.hibernate.tuple.entity.PojoEntityTuplizer]
PropertyAccessException 2: org.springframework.beans.MethodInvocationException: Property 'transportIds' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/spring/database.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Unable to instantiate default tuplizer [org.hibernate.tuple.entity.PojoEntityTuplizer]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1361)
The system is a mix of Spring 2.5, Hibernate 3.2, Cxf 2.3.4, Javassist 3.11,
该系统混合了 Spring 2.5、Hibernate 3.2、Cxf 2.3.4、Javassist 3.11、
My questions are:
我的问题是:
(a) Is this the correct approach?
(a) 这是正确的方法吗?
(b) The error occurs as soon as I introduce
(b) 我一引入就出现错误
<union-subclass name="Ref1" table="REF1" extends="Ref" />
<union-subclass name="Ref2" table="REF2" extends="Ref" />
so I guess this is not the best way of doing it?
所以我想这不是最好的方法吗?
(c) Can it be written with annotations? I cannot fathom how to define the Ref1 and Ref2 classes without actually creating a POJO class for them. (d) Can I user more than 1 level of inheritance? I'd like, for example, use an abstract superclass for all my concrete tables, that cover the auditing fields they all have in common? Let's say class Ref extends an abstract AuditTable class, both in Java and Hibernate mappings.
(c) 可以用注解来写吗?如果没有为它们实际创建 POJO 类,我无法理解如何定义 Ref1 和 Ref2 类。(d) 我可以使用超过 1 级的继承吗?例如,我想对我所有的具体表使用抽象超类,以涵盖它们共有的审计字段?假设类 Ref 在 Java 和 Hibernate 映射中扩展了一个抽象的 AuditTable 类。
采纳答案by Joel Hudon
If i understand the question correctly, You have a master record table with multiple foreign key to a lot of table that have the same colums each other ?
如果我正确理解了这个问题,您有一个主记录表,其中有多个外键指向许多彼此具有相同列的表?
(a) Is this the correct approach?
(a) 这是正确的方法吗?
No, You are trying to do inheritance by using the Table per class strategy witch i think is not appropriate to use here because you have one reference to each for each type object(field Ref1 and field Ref2 in your case). The use case that can be appropriate to use inheritance is if you have one polymorphic association to Ref in the MasterRecord object
不,您正在尝试通过使用 Table per class 策略来进行继承,我认为这里不适合使用,因为您对每个类型对象都有一个引用(在您的情况下为字段 Ref1 和字段 Ref2)。适合使用继承的用例是,如果您在 MasterRecord 对象中有一个与 Ref 的多态关联
Example of polymorphic association to Ref
与 Ref 的多态关联示例
public class MasterRecord{
Long id;
Ref anyObjectRef1OrRef2; <-- Polymorphic association
}
The association anyObjectRef1OrRef2
would have been map with the <any ... />
element in the mapping of MasterRecord. It would have needed two column one with the className and one for the foreignKey
该关联anyObjectRef1OrRef2
将与<any ... />
MasterRecord 映射中的元素进行映射。它需要两列,第一列是 className,另一列是外键
(b)The error occurs as soon as I introduce
<union-subclass
... so I guess this is not the best way of doing it?
(b) 我一介绍就会出现错误
<union-subclass
......所以我想这不是最好的方法吗?
What you should do is inherit properties from a superclass (no specific table for this superclass)
你应该做的是从超类继承属性(这个超类没有特定的表)
(C)Can it be written with annotations?
(C) 可以用注解来写吗?
Yes use @MappedSuperclass annotation.
Hibernate reference Implementation (Using Annotation)
是的,使用 @MappedSuperclass 注释。
Hibernate 参考实现(使用注解)
- Mapping inheritancesee section 2.2.4.4. Inherit properties from superclasses
- 映射继承见第 2.2.4.4 节。从超类继承属性
(C-a)I cannot fathom how to define the Ref1 and Ref2 classes without actually creating a POJO class for them?
(Ca) 我无法理解如何定义 Ref1 和 Ref2 类而不实际为它们创建 POJO 类?
It can't be done without creating Ref1 and Ref2 pojo classes.
不创建 Ref1 和 Ref2 pojo 类就无法完成。
(d)Can I use more than 1 level of inheritance? I'd like, for example, use an abstract superclass for all my concrete tables, that cover the auditing fields they all have in common? Let's say class Ref extends an abstract AuditTable
(d) 我可以使用超过 1 级的继承吗?例如,我想对我所有的具体表使用抽象超类,以涵盖它们共有的审计字段?假设类 Ref 扩展了一个抽象的 AuditTable
Example with annotation
带注释的示例
Base Class Ref.java
基类 Ref.java
@MappedSuperclass
public abstract class Ref {
String value;
}
Class Ref1.java
类 Ref1.java
@Entity
public class Ref1 extends Ref {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
}
Class Ref2.java
类 Ref2.java
@Entity
public class Ref2 extends Ref {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
}
Class MainRecord.java
类 MainRecord.java
@Entity
public class MainRecord {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@ManyToOne(cascade=CascadeType.ALL, targetEntity=Ref1.class)
Ref ref1;
@ManyToOne(cascade=CascadeType.ALL, targetEntity=Ref2.class)
Ref ref2;
}
Create and save entity as follow
创建和保存实体如下
..begin transaction
MainRecord mainRecord = new MainRecord();
Ref1 ref1 = new Ref1();
ref1.setValue("tettset");
Ref2 ref2 = new Ref2();
ref2.setValue("tettset");
mainRecord.setRef2(ref2);
mainRecord.setRef1(ref1);
entitymanager.persist(mainRecord);
..commit transaction.
to use hibernate maping file you would need to remove all annotation use the mapping below.
要使用休眠映射文件,您需要使用下面的映射删除所有注释。
Not that when using a mapping file, the abstract Ref.java
super class is not mapped and all properties of the super class is in each child mapping file.
并不是在使用映射文件时,抽象Ref.java
超类没有被映射,超类的所有属性都在每个子映射文件中。
<class name="MainRecord" table="MAIN_RECORDS">
<id name="id" column="uid" type="long">
<generator class="identity"/>
</id>
<many-to-one name="ref1" class="Ref1" column="ID_REF1" fetch="join" unique="true" cascade="all" />
<many-to-one name="ref2" class="Ref2" column="ID_REF2" fetch="join" unique="true" cascade="all" />
</class>
<class name="Ref1" table="REF1">
<id name="id" column="uid" type="long">
<generator class="identity"/>
</id>
<property name="value" type="java.lang.String" column="VALUE" />
</class>
<class name="Ref2" table="REF2">
<id name="id" column="uid" type="long">
<generator class="identity"/>
</id>
<property name="value" type="java.lang.String" column="VALUE" />
</class>
回答by SJuan76
Just one question.... if you use the same class to access several different tables... To which table will be stored new instances that you save? How will Hibernate know?
只是一个问题......如果你使用同一个类来访问几个不同的表......你保存的新实例将存储到哪个表?Hibernate 如何知道?
AFAIK, this cannot be done.
AFAIK,这是不可能的。
回答by atrain
Shortcuts such as these, even if they can be made to work, often lead down a road of eventual confusion for developers who inherit your code. Before you ask "can it be done", ask "should it be done".
诸如此类的快捷方式,即使可以使它们起作用,通常也会导致继承您代码的开发人员最终陷入混乱。在问“能不能做”之前,先问“应该做吗”。
Think down the road: is it better to be more "efficient" at development time by creating fewer classes and using a somewhat obscure feature, or is it better to just make the separate classes and make things more comprehensible. Also, you might box yourself into a corner because this specific feature might cause unintended consequences, the classic "why is it doing that" situation.
考虑一下:在开发时通过创建更少的类和使用有点晦涩的功能来提高“效率”更好,还是只制作单独的类并使事情更易于理解更好。此外,您可能框自己陷入了困境,因为这种特定的功能可能会导致意想不到的后果,经典的“为什么做那个”的局面。
I've inherited many apps where previous generations of developers wanted to do things in "cool" or "elegant" ways and ended up causing more confusion than if they had kept things concrete and simple.
我继承了许多应用程序,在这些应用程序中,前几代开发人员希望以“酷”或“优雅”的方式做事,结果导致比让事情具体和简单的情况更多的混乱。
Just create the separate classes.
只需创建单独的类。