簡體   English   中英

覆蓋Hibernate注釋

[英]Override Hibernate Annotations

我正在開發一個使用Hibernate並連接到Oracle實例的Java應用程序。 另一個客戶端希望使用相同的應用程序,但要求它在MS SQL Server上運行。 我想避免對現有注釋進行更改,而是創建一個xml文件包,我們可以根據環境將其放入。

一種方法是使用JPA XML配置覆蓋現有的類注釋。 但是,JPA不支持通用生成器,由於我們的遺留數據庫的結構,這是一個要求。 我正在研究的另一種方法是使用Hibernate XML配置重新映射整個類並訪問generator xml標記。 這個解決方案有一些問題:

  • Hibernate不允許您有選擇地覆蓋實體成員
  • Hibernate不允許您重新映射同一個類(例如org.hibernate.AnnotationException: Use of the same entity name twice

有沒有人有使用Hibernate XML配置文件覆蓋注釋的經驗,或者JPA是唯一的方法嗎?

使用示例進行更新

在Oracle中,序列用於在將新記錄插入數據庫時​​生成唯一ID。 然后以下列方式注釋id:

@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沒有Sequences的概念(思想差異)。 因此,您可以使用表生成器來模擬序列。

@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的本機ID生成器(也需要不同的注釋)。

為了解決這個問題,我研究了使用Hibernate的@GenericGenerator並將其指向我自己的一個類,它創建了org.hibernate.id.SequenceGenerator (或類似的東西)的模型,並通過擴展org.hibernate.id.TableStructure定義表的結構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;
}

此解決方案需要使用新的Id生成器修改每個Hibernate實體。

我認為如果在配置SessionFactory時不使用AnnotationConfiguration ,則會省略注釋。

所以,使用Configuration

對於您的生成器問題(解決方案通常是“使用本機生成器”但由於使用遺留數據庫而無法為您工作),您可以擴展SQLServerDialect並覆蓋getNativeIdentifierGeneratorClass以返回(可能是自定義的) )生成器,為您的遺留數據庫提供所需的功能。

我之前在Grails(GORM)應用程序中遇到了混合n-match遺留與新模式/數據庫的需求,當然它正在運行Hibernate 3。

不會說“你做錯了” - 但是我會將JPA @Annotations保留到像@Entity和@Column這樣的基礎知識中,並將它留給Hibernate 方言 ,這也是在XML配置文件中指定的。

您可以嘗試將Oracle10gDialect子類化為一個為所有表分配序列生成器的子類,而不是Sybase的子類。

請參閱此帖子 ,了解如何實現此目的。

更新:詹姆斯和我建議(幾乎在同一分鍾內)是設置persistence.xml文件的多個持久性單元部分。

這允許使用@Entity和@Id而不提供類中的詳細信息。 詳細信息來自hibernate.dialect屬性。 我建議繼承Oracle10gDialect(和james SQLServerDialect) - 那些會選擇表命名,id生成器策略等。

請參閱 - > https://forum.hibernate.org/viewtopic.php?f=1&t=993012

如果重寫HBM XML文件中的注釋,則可以維護兩組這樣的XML,並通過Hibernate的映射指令選擇要使用的XML。 我在Hibernate Core中完成了這個,但是在J2EE / JPA環境中沒有這樣做,所以我不知道在這方面是否有任何問題。

最大的缺點是刪除所有注釋並在XML中重建它們可能需要做很多工作。

就我而言:

機架和插槽是具有自定義ID生成器的實體。 我正在使用單向一對一映射。 維度表將使用自動生成的自定義ID作為多個表的外鍵來保存數據(例如,此處為機架和插槽)。 我的模式如下所示:Rack ------> Dimension <----------- Slot其中Dimension將保存帶有生成ID的Rack和Slot表的數據。

這里關注的是,當我保存這樣的數據: -

Rack rack = new Rack(params);
Dimension dim = new Dimension(params);
rack.setDimension(dim);
session.save(rack);

在Rack和Dimension Tables中使用相同的Autogenerated ID成功保存數據。

但是當我保存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

我可以在保存Slot和Dimension的數據時將動態屬性名稱作為“slot”傳遞,並在保存Rack和Dimension的數據時將其傳遞給“rack”。


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

我會說,如果您的注釋是特定於數據庫的,那么您做錯了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM