22

古いデータベース スキーマ用の休止状態アダプタを作成しようとしています。このスキーマには専用の id 列はありませんが、他の約 3 つの列を使用してデータを結合しています。

一部のテーブルでは、合体を使用する必要があります。これは私がこれまでに思いついたものです:

定義について:

  • 車には、車のユーザーまたは車のユーザー グループによって割り当てられた要素を含めることができます。
  • FORIGN_ELEMENT がユーザーの名前を保持している場合、定義は「u」になります。
  • FORIGN_ELEMENT がグループの名前を保持している場合、定義は 'g' になります。
  • これは、1 つのテーブル (CAR_TO_ELEMENT) が、車を要素に、車グループを要素にマッピングするために悪用されていることも意味します。スーパークラスの CarElement と、サブクラスの CarUserElement および CarGroupElement を定義しました。
  • 状態は「アクティブ」または興味のない文字列のいずれかです
  • 定義と状態を別の場所に設定します。これについて心配する必要はありません。
  • 結合テーブルで DEP_NR を使用します。ゼロの場合は、USR_DEP_NR を使用します。私はCOALESCE(NULLIF())ネイティブ SQL でこれを成功させ、Pojos を使用して Hibernate で同じことを達成したいと考えています。

さて、ここでコードに行きます:

@Entity
@Table(name="CAR")
public class Car extends TableEntry implements Serializable {
    @Id
    @Column(name="DEP_NR")
    private int depnr;

    @Id
    @Column(name="USER_NAME")
    @Type(type="TrimmedString")
    private String username;

    @ManyToOne(fetch = FetchType.EAGER, targetEntity=CarGroup.class)
    @JoinColumns(value={ 
            @JoinColumn(name="GROUP_NAME"),
            @JoinColumn(name="DEP_NR"),
            @JoinColumn(name="state"),
    })
    private CarGroup group;

    @OneToMany(fetch=FetchType.EAGER, targetEntity=CarUserElement.class, mappedBy="car")
    private Set<CarUserElement> elements;
}
@Entity
@Table(name="CAR_GROUP")
public class CarGroup extends TableEntry implements Serializable {
    @Id
    @Column(name="DEP_NR")
    private int depnr;

    @Id
    @Column(name="GROUP_NAME")
    @Type(type="TrimmedString")
    private String group;

    @ManyToOne(fetch = FetchType.EAGER, targetEntity=Car.class)
    @JoinColumns(value={ 
            @JoinColumn(name="GROUP_NAME"),
            @JoinColumn(name="DEP_NR"),
            @JoinColumn(name="state"),
    })
    private Set<Car> cars;

    @OneToMany(fetch=FetchType.EAGER, targetEntity=CarGroupElement.class, mappedBy="car")
    private Set<CarGroupElement> elements;
}
@MappedSuperclass
public class CarElement extends TableEntry {
    @Id
    @ManyToOne(fetch = FetchType.EAGER, targetEntity=Element.class)
    @JoinColumns(value={ 
            @JoinColumn(name="ELEMENT_NAME"),
            @JoinColumn(name="state"),
    })
    private Element element;
}
@Entity
@Table(name="CAR_TO_ELEMENT")
public class CarUserElement extends CarElement {
    @Id
    @Column(name="DEFINITION")
    private char definition;

    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumnsOrFormulas(value = {
        @JoinColumnOrFormula(formula=@JoinFormula(value="COALESCE(NULLIF(DEP_NR, 0), USR_DEP_NR)", referencedColumnName="DEP_NR")),
        @JoinColumnOrFormula(column=@JoinColumn(name="FORIGN_ELEMENT", referencedColumnName="USER_NAME")),
        @JoinColumnOrFormula(column=@JoinColumn(name="STATE", referencedColumnName="STATE"))
    })
    private Car car;

}
@Entity
@Table(name="CAR_TO_ELEMENT")
public class CarGroupElement extends CarElement {
    @Id
    @Column(name="DEFINITION")
    private char definition;

    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumnsOrFormulas(value = {
        @JoinColumnOrFormula(formula=@JoinFormula(value="COALESCE(NULLIF(DEP_NR, 0), USR_DEP_NR)", referencedColumnName="DEP_NR")),
        @JoinColumnOrFormula(column=@JoinColumn(name="FORIGN_ELEMENT", referencedColumnName="GROUP_NAME")),
        @JoinColumnOrFormula(column=@JoinColumn(name="STATE", referencedColumnName="STATE"))
    })
    private Car car;

}

利用可能なすべてのバージョンの hibernate (3.5.1 [最初のバージョン@JoinColumnsOrFormulas] から 4.xx まで) を試しましたが、常に次のエラーが発生します。

Exception in thread "main" java.lang.ClassCastException: org.hibernate.mapping.Formula cannot be cast to org.hibernate.mapping.Column
    at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:351)
    at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1338)
    at org.hibernate.cfg.annotations.CollectionBinder.bindOneToManySecondPass(CollectionBinder.java:791)
    at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:719)
    at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:668)
    at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:66)
    at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1597)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1355)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1737)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1788)

他の休止状態のユーザーも同じ問題を抱えているようです。どのバージョンでも動作しません。このスレッドとその他のスタックオーバーフローの質問を参照してください: https://forum.hibernate.org/viewtopic.php?f=1&t=1010559

より完全にするために、ここに私の TrimmedString クラスがあります :

前もって感謝します!

PS: これら 3 つの列を 1 つの DEP-NR-Column (つまり、@ JoinColumns のみを使用して DEP_NRまたはUSR_DEP_NR) と結合するだけで機能します。しかし、私はこれが必要coalesce(nullif())です。

4

3 に答える 3

4

同様の問題に遭遇しました。問題は、@Id 内で @Formula を使用していることにあるようです。Hibernate は Id を挿入可能にする必要があり、式は読み取り専用です。

私の場合、個々の列 Id プロパティを独自に作成し、結合されたオブジェクトを別のプロパティにすることで、問題を回避できました。数式で 2 つの異なる列を使用しているため、これが機能するかどうかはわかりませんが、その場合、コードは次のようになります。

@Entity
@Table(name="CAR_TO_ELEMENT")
public class CarUserElement extends CarElement {
    @Id
    @Column(name="DEFINITION")
    private char definition;

    @Id
    @Column(name="DEP_NR")
    private Integer depNr;

    @Id
    @Column(name="USR_DEP_NR")
    private Integer usrDepNr;

    @Id
    @Column(name="FORIGN_ELEMENT")
    private String userName;

    @Id
    @Column(name="STATE")
    private String state;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumnsOrFormulas(value = {
        @JoinColumnOrFormula(formula=@JoinFormula(value="COALESCE(NULLIF(DEP_NR, 0), USR_DEP_NR)", referencedColumnName="DEP_NR")),
        @JoinColumnOrFormula(column=@JoinColumn(name="FORIGN_ELEMENT", referencedColumnName="USER_NAME", insertable = false, updatable = false)),
        @JoinColumnOrFormula(column=@JoinColumn(name="STATE", referencedColumnName="STATE", insertable = false, updatable = false))
    })
    private Car car;

}
于 2015-08-14T13:22:32.027 に答える