Hibernate наследование и несколько таблиц с одним и тем же классом - PullRequest
3 голосов
/ 29 июля 2011

Я довольно новичок в Hibernate.В моей ситуации у меня есть конкретная таблица с записями, содержащими идентификаторы соединения с множеством других таблиц - все с одинаковой структурой.Чего я хотел бы добиться, так это получить что-то вроде

SELECT * 
  FROM main_records mr, ref1 r1, ref2 r2 
 WHERE r1.id = mr.id_ref1 
   AND r2.id = mr.id_ref2;

Основная идея заключается в повторном использовании класса для всех ссылок на соединения.

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
)

Я настроил базовые классы POJO

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
}

Моя идея состоит в том, чтобы определить отображения Hibernate следующим образом:

Определение абстрактного суперкласса

<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>

Отображение основного объекта, расширение суперкласса, но использование отдельных таблиц

<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>

Я вручную включаю файлы сопоставления в конфигурацию, загрузка кажется нормальной, но затем происходит ошибка, без каких-либо подробных объяснений:

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)

Система представляет собой смесь Spring 2.5, Hibernate 3.2, Cxf 2.3.4, Javassist 3.11,

Мои вопросы:

(a) Это правильный подход?

(b) Ошибка возникает, как только я ввожу

<union-subclass name="Ref1" table="REF1" extends="Ref" />
<union-subclass name="Ref2" table="REF2" extends="Ref" />

так что я полагаю, это не лучший способ сделать это?

(c) Можно ли это написать с аннотациями?Я не могу понять, как определить классы Ref1 и Ref2 без фактического создания для них класса POJO.(d) Могу ли я использовать более 1 уровня наследования?Я хотел бы, например, использовать абстрактный суперкласс для всех моих конкретных таблиц, которые охватывают области аудита, которые у них всех общие?Допустим, класс Ref расширяет абстрактный класс AuditTable как в Java, так и в отображениях Hibernate.

Ответы [ 3 ]

1 голос
/ 30 июля 2011

Если я правильно понял вопрос, у вас есть таблица основных записей с несколькими внешними ключами для множества таблиц, которые имеют одинаковые столбцы друг с другом?

(a) Является ли это правильным подходом?

Нет, вы пытаетесь осуществить наследование, используя стратегию «Таблица на класс», которую я считаю нецелесообразной для использованияздесь, потому что у вас есть одна ссылка на каждый для каждого типа объекта (поле Ref1 и поле Ref2 в вашем случае).Вариант использования, который может быть подходящим для использования наследования, - это если у вас есть одна полиморфная ассоциация с Ref в объекте MasterRecord

Пример полиморфной ассоциации с Ref

public class MasterRecord{

    Long id;

    Ref anyObjectRef1OrRef2; <-- Polymorphic association
}

Ассоциация anyObjectRef1OrRef2 была бы отображена с элементом <any ... /> в отображении MasterRecord.Потребовалось бы два столбца один с className и один для foreignKey

(б) Ошибка возникает, как только я ввожу <union-subclass ... так что я думаю, это не лучший способделать это?

Что вам нужно сделать, это наследовать свойства от суперкласса (нет конкретной таблицы для этого суперкласса)

(C) Можно ли писать с аннотациями?

Да, используйте аннотацию @MappedSuperclass.
Ссылка на Hibernate Реализация (с использованием аннотации)

(Ca) Я не могу понять, как определить классы Ref1 и Ref2 без фактического создания для них класса POJO?

Можетне может быть сделано без создания классов pojo Ref1 и Ref2.

(d) Могу ли я использовать более 1 уровня наследования?Я хотел бы, например, использовать абстрактный суперкласс для всех моих конкретных таблиц, которые охватывают области аудита, которые у них всех общие?Допустим, класс Ref расширяет абстрактную таблицу AuditTable

Пример с аннотацией

Базовый класс Ref.java

@MappedSuperclass
public abstract class Ref {

    String value;

}

Класс Ref1.java

@Entity
public class Ref1 extends Ref {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;
}

Класс Ref2.java

@Entity
public class Ref2 extends Ref {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;
}

Класс 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;
}

Создание и сохранение объекта следующим образом

..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.

виспользуйте файл отображения hibernate, вам нужно удалить все аннотации, используйте приведенное ниже отображение.

Не то чтобы при использовании файла отображения абстрактный класс 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>
0 голосов
/ 29 июля 2011

Ярлыки, подобные этим, даже если их можно заставить работать, часто ведут к путанице в конечном итоге для разработчиков, которые наследуют ваш код.Прежде чем спросить «можно ли это сделать», спросите «должно ли это быть сделано».

Подумайте о будущем: лучше ли быть более «эффективным» во время разработки, создав меньше классов и используя несколько непонятныхособенность, или лучше просто сделать отдельные классы и сделать вещи более понятными.Кроме того, вы можете загнать себя в угол, потому что эта особенность может привести к непредвиденным последствиям, классической ситуации «почему она делает , что ».

Я унаследовал многие приложения, где предыдущие поколенияиз разработчиков хотели делать что-то «круто» или «изящно», и в итоге это вызывало больше путаницы, чем если бы они делали вещи конкретными и простыми.

Просто создайте отдельные классы.

0 голосов
/ 29 июля 2011

Всего один вопрос .... если вы используете один и тот же класс для доступа к нескольким различным таблицам ... В какой таблице будут храниться новые экземпляры, которые вы сохраните?Как Hibernate узнает?

AFAIK, это невозможно сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...