23

TL;DRにプロパティを追加せずに、Hibernate スキーマの作成を強制して、コンクリートクラスごとのテーブル設定で外部キー制約を作成するにはどうすればよいAbstractProperty.ownerIdですか?Owner.ownerIdOwnerAbstractProperty

次のクラス構造を持つプロジェクトに取り組んでいます。

クラス構造のサンプル

には、クラスによって拡張されるOwnerへの 1 対 1 のマッピングがあります (および のようなものもありますが、この質問の残りの部分にはあまり関係ありません)。AbstractPropertyConcretePropertyAnotherProperty

には、AbstractProperty実際には 1 つのプロパティしかありませんabstractPropertyId。そのため、table-per-concrete-class構造を使用して、最終的に、他の拡張クラス ( ) の table OwnerConcreteProperty、および table を使用します。AbstractPropertyAnotherProperty

このために、次のマッピングを作成しましたOwner

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.example">
    <class name="Owner">
        <id name="ownerId">
            <generator class="identity"/>
        </id>
        <property name="ownerProperty"/>
        <one-to-one name="abstractProperty"/>
    </class>
</hibernate-mapping>

そしてのためにAbstractProperty

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.example">
    <class name="AbstractProperty" abstract="true">
        <id name="ownerId">
            <generator class="foreign">
                <param name="property">ownerId</param>
            </generator>
        </id>
        <union-subclass name="ConcreteProperty">
            <property name="concreteProperty"/>
        </union-subclass>
        <union-subclass name="AnotherProperty">
            <property name="anotherProperty"/>
        </union-subclass>
    </class>
</hibernate-mapping>

これは機能します。

ただし、これが私の質問です。このマッピングを使用し、Hibernate にスキーマを作成させます ( )。データベース フィールドからフィールドへの<property name="hbm2ddl.auto">create</property>外部キー制約は作成されません。このマッピングを使用してからへの逆制約付き 1 対 1 フィールドを作成すると、次のようになります(フィールドの型はJava クラスです)。ConcreteProperty.ownerIdOwner.ownerIdAbstractPropertyOwnerAbstractPropertyownerOwnerAbstractProperty

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.example">
    <class name="AbstractProperty" abstract="true">
        <id name="ownerId">
            <generator class="foreign">
                <param name="property">ownerId</param>
            </generator>
        </id>
        <one-to-one name="owner" constrained="true"/>
        <union-subclass name="ConcreteProperty">
            <property name="concreteProperty"/>
        </union-subclass>
        <union-subclass name="AnotherProperty">
            <property name="anotherProperty"/>
        </union-subclass>
    </class>
</hibernate-mapping>

でこのフィールドAbstractProperty.ownerIdを使用せずに外部キーの作成を強制するにはどうすればよいですか?Owner.ownerIdOwnerAbstractProperty

4

4 に答える 4

1

簡単な答え: Hibernate に実際のアプリケーションのスキーマを作成させないでください。

Hibernate はオブジェクト リレーショナル マッパーであり、これとして扱う必要があります。

Hibernate が追加でスキーマを作成するのは、初めてのことです。しかし、最初のリリース以降の環境では、Hibernate にスキーマを制御させたくないでしょう。結局、SQL を処理して移行スクリプトを作成する必要があります (手動またはツール サポート)。最初のリリースの後、データベースにデータがあります。本番システムで問題の少ないデータ移行を確実に行うには、開発環境と同じように本番環境でもスキーマとデータの移行を検討する必要があります。

その例外は、データが失われたときに高速に再構築できる可能性がある、めったに変更されないデータを持つアプリケーションである可能性があります。

于 2015-05-12T12:30:15.693 に答える
0

最初 : Hibernate/JPA は多くのシナリオを処理することができます。あなたと同じアプローチを試みている人が本当にたくさんいたとしたら、今では対処されていると思います。それは春のチキンではありません。**それは手がかりです;-) **

2番目: 「ownerProperty」を持つ「Owner」というテーブルを持つことは、別の手がかりです。名前は、組み込みの関係を示唆しています。

3 番目: AbstractProperty テーブル内に所有者プロパティが必要ないことを単に述べるだけで、一般に catch-22 ( http://en.wikipedia.org/wiki/False_dilemma )と呼ばれる論理的誤謬の舞台が設定されます。 .

私のポイント - >これは、技術的/フレームワークの問題というよりも、モデリング/設計の問題のようです。

私の提案は、問題から一歩下がって、再評価することです。たとえば、spring-jdbc で単純なクエリを作成しただけの場合、SELECT、UPDATE、および DELETE 操作のデータをどのように操作すると予想されますか? ... これらを解決すれば、解決策やニーズがより明確になる可能性があります。さらに指摘すると、カスケード削除ではどのような動作になると思いますか? 単一の Owner レコードに対して DELETE ステートメントを発行した場合、データベースが子テーブルからレコードを自動的に削除するようにしますか? 再帰的に?それを分離したら、Hibernate に何をすべきかを伝える方法を理解できます。ソリューションを時期尚早に制限して、チーム メンバーがカートを馬の前に置くことを許可しないでください。

たとえば、(ケース 1) 所有者の「プロパティ」を実際に扱っている場合、所有者に関する複数のプロパティ (別名: OneToMany) を保存する必要があることは十分に予測できます。

または、(ケース 2) 所有者の「タイプ」を扱っている場合 (識別子フィールドのように)、「AbstractProperty」テーブルは所有者を拡張する必要があります...その場合、ソリューションを減らすことができる場合があります3 つまでのテーブル (ディスクリミネーターを持つ所有者、所有者 ID を持つ Concrete1、所有者 ID を持つ Concrete2 )。

提案された解決策 1 : いずれの場合でも、「AbstractProperty」テーブルがその親/所有者への参照を持つことは依然として理にかなっています。もしそうなら、Cascading DELETES はあなたが好む方法で機能すると思います。

提案された解決策 2 : ただし、Owner レコードのカスケード削除シナリオで、AbstractProperty の行を参照データとして残したい場合は、Owner とレコードの間に追加のテーブルを配置する必要があると主張できます。参照データを保護する AbstractProperty ... 一意の複合キーを持つマッピング テーブルとして。

ビジネス ニーズとユーザー ストーリーに焦点を当てることで、利用可能なソリューションを選択する際の指針となることを願っています。

于 2015-03-19T01:53:31.687 に答える
0

Abstract Property の Owner 属性を「 transient 」と定義すると、自動的に機能しませんか?

変数は、オブジェクトの永続状態の一部ではないことを示すために一時的とマークされる場合があります。

また、独自の手動シリアライゼーションを実装する場合は、フィールドの Modifier をチェックして無視することができます --> 循環シリアライゼーションの問題は回避されます。

私が見る唯一の他の方法は、具体的な Property クラスのそれぞれに Owner 属性をプッシュし、マッピングを次のように変更することです

<class name="AbstractProperty" abstract="true">
    <id name="ownerId">
        <generator class="foreign">
            <param name="property">ownerId</param>
        </generator>
    </id>

    <union-subclass name="ConcreteProperty">
        <property name="concreteProperty"/>
        <one-to-one name="owner" constrained="true"/>
    </union-subclass>
    <union-subclass name="AnotherProperty">
        <property name="anotherProperty"/>
        <one-to-one name="owner" constrained="true"/>
    </union-subclass>
</class>

次のSQLを作成します。

create table AnotherProperty (
    ownerId integer not null,
    anotherProperty varchar(255),
    primary key (ownerId)
)

create table ConcreteProperty (
    ownerId integer not null,
    concreteProperty varchar(255),
    primary key (ownerId)
)

create table Owner (
    ownerId integer generated by default as identity,
    ownerProperty varchar(255),
    primary key (ownerId)
)

alter table AnotherProperty 
    add constraint FK_ceq89n6x2i1ax18bb4gqpq4m5 
    foreign key (ownerId) 
    references Owner

alter table ConcreteProperty 
    add constraint FK_i41buhvtxxtpsim2cc0ur1gxr 
    foreign key (ownerId) 
    references Owner
于 2013-08-09T13:03:14.570 に答える
0

標準の JPA (休止状態固有のハックなし) を使用していますが、同じ問題があり、適切な解決策が見つかりませんでした。

仮定:

  1. AbstractPropertyさまざまなアプリケーションで再利用可能/共有されるパッケージ内のクラスであり、アプリケーション固有のクラスへの参照は必要ありませんOwner
  2. ConcreteProperty&AnotherPropertyはアプリケーション固有です。

この場合の解決策はConcretePropertyOwner(外部キーを使用して) への参照を配置し、最終的AnotherPropertyには同じ を拡張しApplicationPropertyabstractPropertyIdプライベートにすることで、所有者の設定時に自動的に設定されるようにすることです。

于 2013-08-07T20:42:35.427 に答える