Ответ 1
Я думаю, что если вы не используете AnnotationConfiguration
при настройке SessionFactory
, аннотации будут опущены.
Итак, используйте Configuration
.
Я разрабатываю Java-приложение, которое использует Hibernate и связано с экземпляром Oracle. Другой клиент хочет использовать одно и то же приложение, но требует его запуска на MS SQL Server. Я хотел бы избежать внесения изменений в существующие аннотации и вместо этого создать пакет xml файлов, которые мы можем удалить в зависимости от среды.
Один из способов сделать это - использовать конфигурацию JPA XML для переопределения существующих аннотаций классов. Однако JPA не поддерживает генераторные генераторы, что является требованием из-за структуры нашей старой базы данных. Другой способ, которым я занимаюсь, - использовать Hibernate XML configs для переназначения целых классов и доступа к тегу generator
xml. Это решение имеет некоторые проблемы:
org.hibernate.AnnotationException: Use of the same entity name twice
)Есть ли у кого-нибудь опыт переопределения аннотаций с использованием файлов конфигурации Hibernate XML или JPA - единственный способ?
В Oracle, Последовательности используются для генерации уникальных идентификаторов при вставке новых записей в базу данных. Затем идентификатор будет аннотирован следующим образом:
@Id
@GeneratedValue(generator="EXAMPLE_ID_GEN", strategy=GenerationType.SEQUENCE)
@SequenceGenerator(name="EXAMPLE_ID_GEN", sequenceName="SEQ_EXAMPLE_ID")
@Column(name = "EXAMPLE_ID")
public String getExampleId() {
return this.exampleId;
}
Однако MS SQL Server не имеет концепции последовательностей (идеологических различий). Поэтому вы можете использовать генератор таблицы для имитации последовательностей.
@Id
@GeneratedValue(generator="EXAMPLE_ID_GEN", strategy=GenerationType.TABLE)
@TableGenerator(name="EXAMPLE_ID_GEN", tableName="SEQUENCE", valueColumnName="VALUE", pkColumnName="SEQUENCE", pkColumnValue="EXAMPLE_ID")
public String getExampleId() {
return this.exampleId;
}
Две различные конфигурации для двух разных типов баз данных. Имейте в виду, что это устаревшая база данных, и мы не собираемся переписывать наше приложение для поддержки идентификаторов SQL Server, собственного генератора идентификаторов для SQL Server (для чего также потребуется другая аннотация).
Чтобы облегчить это, я рассмотрел использование Hibernate @GenericGenerator
и назовет его классу собственного создания, которое моделирует org.hibernate.id.SequenceGenerator
(или что-то подобное), а также настраивает структуру таблицы, расширяя org.hibernate.id.TableStructure
.
Вернуться к исходному вопросу - возможно ли это с помощью переопределения XML?
Итак, в конце концов, я обнаружил, что JPA и Hibernate не предоставляют функциональные возможности, которые я искал. Вместо этого я создал специальный генератор, который проверил диалоги базы данных и соответствующим образом установил TableStructure. Когда я изучил все варианты, я закончил использование аннотации Hibernate @GenericGenerator
. Это пример аннотации генерации Id:
@Id
@GeneratedValue(generator="EXAMPLE_ID_GEN")
@GenericGenerator(name = "EXAMPLE_ID_GEN", strategy="com.my.package.CustomIdGenerator", parameters = {
@Parameter(name = "parameter_name", value="parameter_value")
})
public String getExampleId() {
return this.exampleId;
}
Это решение требует, чтобы каждый объект Hibernate был модифицирован с помощью нового генератора Id.
Я думаю, что если вы не используете AnnotationConfiguration
при настройке SessionFactory
, аннотации будут опущены.
Итак, используйте Configuration
.
Для вашей проблемы с генератором (для которой обычно было бы использовать "родной генератор", но не работает для вас из-за работы с устаревшим db), возможно, вы можете расширить SQLServerDialect и переопределить getNativeIdentifierGeneratorClass, чтобы вернуть (возможно, настраиваемый) генератор, который делает то, что вам нужно для вашего старого db.
Если вы переписываете аннотации в XML файлах HBM, вы можете поддерживать два набора таких XML и выбирать, какие из них использовать с помощью директив сопоставления Hibernate. Я сделал это в Hibernate Core, но не в среде J2EE/JPA, поэтому я не знаю, есть ли какие-либо ошибки в этом отношении.
Самый большой недостаток - это, вероятно, большая работа, чтобы удалить все ваши аннотации и перестроить их в XML.
Я бы сказал, что если ваши аннотации являются специфичными для базы данных, вы делаете это неправильно.
Я столкнулся с необходимостью сочетать n-match legacy с новыми схемами/базами данных в приложении Grails (GORM), которое, конечно же, запускает Hibernate 3 под ним.
Не сказал бы "вы делаете это неправильно" - но я бы сохранил JPA @Annotations до самых оснований, таких как @Entity и @Column, и оставьте его на диалекте Hibernate, который также указан в файле конфигурации XML.
Вы можете поэкспериментировать с подклассом Oracle10gDialect с тем, который назначает генератор последовательности для всех таблиц, а не Sybase, который этого не делает.
Пожалуйста, просмотрите сообщение о том, как это реализовать.
UPDATE: Что мы и Джеймс предлагаем (почти в ту же минуту), это настроить несколько секций последовательности сохранения вашего файла persistence.xml.
Это позволяет использовать @Entity и @Id без предоставления деталей в классе. Подробности поступают в свойство hibernate.dialect
. Я предложил подклассифицировать Oracle10gDialect (и james SQLServerDialect) - это сделало бы выбор в отношении именования таблиц, стратегии генерации идентификатора и т.д.
Смотрите → https://forum.hibernate.org/viewtopic.php?f=1&t=993012
В моем случае:
Стойка и слот - это объекты, имеющие пользовательские генераторы идентификаторов. Я использую однонаправленное отображение "один к одному". Таблица измерений хранит данные с помощью Autogenerated Custom ID в качестве внешнего ключа для нескольких таблиц (например, Rack и Slot). И моя схема выглядит следующим образом: Rack ------ > Dimension < ----------- Slot где Dimension будет содержать данные для таблицы Rack и Slot сгенерированным идентификатором.
Здесь беспокойство заключается в том, что когда я сохраняю данные следующим образом: -
Rack rack = new Rack(params);
Dimension dim = new Dimension(params);
rack.setDimension(dim);
session.save(rack);
Данные сохраняются успешно с тем же Автогенерированным идентификатором в таблицах Rack и Dimension.
Но когда я сохраняю данные для таблицы Slot:
Slot Slot = new Slot(params);
Dimension dim = new Dimension(params);
slot.setDimension(dim);
session.save(slot);
отображается сообщение об ошибке: -
attempted to assign id from null one-to-one property: rack
Могу ли я передать динамическое имя свойства в качестве "слота" при сохранении данных для слотов и измерений и "стойки" при сохранении данных для Rack и Dimension.
@GenericGenerator(name = "foreign", strategy = "foreign", parameters = {
@Parameter(name = "property", value = "slot"),
@Parameter(name = "property", value = "rack")})
Rack.java
@Entity
@Table(name="tablename")
@GenericGenerator(name = "customseq", strategy = "CustomIdGenerator")
public class Rack {
@Id
@GeneratedValue(generator = "customseq")
@Column(name = "uni_id")
private String id;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private Dimension dimension;
// Getters and Setters
}
Slot.java
@Entity
@Table(name="tablename")
@GenericGenerator(name = "customseq", strategy = "CustomIdGenerator")
public class Rack {
@Id
@GeneratedValue(generator = "customseq")
@Column(name = "uni_id")
private String id;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private Dimension dimension;
// Getters and Setters
}
Dimension.java
public class Dimension implements Serializable{
@Id
@Column(name = "systemid")
@GeneratedValue(generator = "foreign")
@GenericGenerator(name = "foreign", strategy = "foreign", parameters = {
@Parameter(name = "property", value = "slot"),
@Parameter(name = "property", value = "rack")})
private String systemid;
@OneToOne(mappedBy = "dimension", fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
private Rack rack;
@OneToOne(mappedBy = "dimension", fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
private Slot slot;
// Getters and Setters
}