7

Tomcat Web アプリで実行されている Maven-Spring-Hibernate-MySql では、hibernate ddl を使用して、MySQL5InnoDBDialect で DB スキーマを生成しています。

スキーマは、外部キーのカスケード オプションを除いて問題なく生成されます。たとえば、私はこの構造を持っています:

ユーザー詳細オブジェクトを保持するユーザー オブジェクト。両方とも同じキーを共有します。

@Entity
@Table(name = "Users")
public class User implements Serializable {

    private static final long serialVersionUID = -359364426541408141L;

    /*--- Members ---*/

    /**
     * The unique generated ID of the entity.
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "User_Id")
    protected long id;

    @Getter
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "user", optional = true)
    protected UserDetails userDetails;

...

}

そしてユーザーの詳細:

@Entity
@Table(name = "UserDetails")
public class UserDetails implements Serializable {

    private static final long serialVersionUID = 957231221603878419L;

    /*--- Members ---*/

    /**
     * Shared Key
     */
    @Id
    @GeneratedValue(generator = "User-Primary-Key")
    @GenericGenerator(name = "User-Primary-Key", strategy = "foreign", parameters = { @Parameter(name = "property", value = "user") })
    @Column(name = "User_Id")
    protected long id;

    @Getter
    @Setter
    @OneToOne(optional = false, fetch = FetchType.LAZY)
    @PrimaryKeyJoinColumn
    private User user;

...

}

スキーマの生成時に、users-details テーブルから users テーブルへの外部キーにカスケードがありません。

ユーザー詳細のスキーマ作成は次のとおりです。

CREATE TABLE `userdetails` (
  `User_Id` bigint(20) NOT NULL,
  `Creation_Time` bigint(20) NOT NULL,
  `EMail` varchar(128) DEFAULT NULL,
  `Enabled` bit(1) NOT NULL,
  `First_Name` varchar(15) DEFAULT NULL,
  `Last_Name` varchar(25) DEFAULT NULL,
  `Password` varchar(64) NOT NULL,
  `User_Name` varchar(15) NOT NULL,
  PRIMARY KEY (`User_Id`),
  UNIQUE KEY `User_Name` (`User_Name`),
  UNIQUE KEY `EMail` (`EMail`),
  KEY `FKAE447BD7BF9006F5` (`User_Id`),
  CONSTRAINT `FKAE447BD7BF9006F5` FOREIGN KEY (`User_Id`) REFERENCES `users` (`User_Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$

ご覧のとおり、「FOREIGN KEY」セクションに「ON DELETE CASCADE」とは書かれていません。

この問題については、こちらこちらでも説明されています。

そこで、userDetails メンバーの上に @OnDelete アノテーションを追加しようとしましたが、うまくいきませんでした..

次に、supportsCascadeDelete をオーバーライドする独自の方言を作成しました。

public class MySql5Dialect extends MySQL5InnoDBDialect {

    public MySql5Dialect() {
    super();
    }

    @Override
    public String getTableTypeString() {
    return " ENGINE=InnoDB DEFAULT CHARSET=utf8";
    }

    @Override
    public boolean supportsCascadeDelete() {
    return true;
    }

}

でも相変わらず変化なし。スキーマを生成した後も、外部キーのカスケード オプションが "RESTRICT" に設定されています。

ここに画像の説明を入力

この問題を解決する方法はありますか (もちろん手動ではありません)。

アップデート

Angel Villalainの提案に従って、 @OnDelete アノテーションを UserDetails クラスの「ユーザー」メンバーの上に配置しました。これにより、OneToOne 関係のトリックが行われました。削除はカスケードされますが、OnUpdate は制限するように設定されています (まだ)。私の最初の質問に私に-それはどういう意味ですか? 「OnDelete」は非常に簡単です。親を削除すると子も削除されますが、「OnUpdate」オプションの意味は何ですか? 制限/カスケードに設定すると、アプリにどのような影響がありますか?

2 番目の質問は、OneToMany 関係でのカスケードに関するものです。私の User クラスは多くの UserProvider を保持しています。次のコードはUserクラスからのものです。

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinTable(name = "Users_Providers", joinColumns = @JoinColumn(name = "User_Id"), inverseJoinColumns = @JoinColumn(name = "Provider_Id"))
protected Set<UserProvider> userProviders = new HashSet<>(0);

そして、これはUserProviderクラスからの逆の関係です:

@ManyToOne(fetch = FetchType.LAZY)
@JoinTable(name = "Users_Providers", joinColumns = @JoinColumn(name = "Provider_Id", insertable = false, updatable = false), inverseJoinColumns = @JoinColumn(name = "User_Id"))
@OnDelete(action = OnDeleteAction.CASCADE)
protected User user;

したがって、 @OnDelete アノテーションを使用した後、結合テーブルでカスケードを使用して onDelete オプションが表示されることを期待していましたが、そうではありません:(正しく使用しましたか?

最後の質問 - @ElementCollection などの一方向の関係はどうですか? 私のUserDetailsクラスは、役割の ElementCollection を保持します (各ユーザーには 1 つ以上の役割を割り当てることができます)。

@ElementCollection(fetch = FetchType.EAGER, targetClass = Role.class)
@CollectionTable(name = "Users_Roles", joinColumns = @JoinColumn(name = "User_Id", referencedColumnName = "User_Id"))
@Column(name = "Role")
protected Set<Role> roles = new HashSet<Enums.Role>(0);

ロールは単なる列挙型であり、エンティティではないため、ロールから親エンティティを指すことはできません。この場合、onDelete をカスケードする方法はありますか?

4

3 に答える 3

4

注釈があれOnDeleteば、DDL は正しいはずです。をどのように構成しているかSessionFactory、具体的には hbm2ddl.auto パラメータにどの値を使用しているかを確認できますか。

アップデート

  • UserProviderクラスの問題について。まず、マッピングは双方向のように見えますが、一方が所有者側で、もう一方が逆側でなければなりません。つまり、リレーションを所有するのはリレーションを結合テーブルに永続化するものであり、もう一方はmappedByパラメーターでマップする必要があり、リレーションを制御しません。のメンバOneToManymappedBy指しているuserUserProperty逆側になり、 が所有者側になり、注釈UserPropertyが必要になります。OnDeleteしかし、念のために明日テストさせてください。私は自分の開発ステーションの前にいるわけではありません。
于 2012-12-24T00:51:45.917 に答える
2

この問題を調査した後、DB スキーマの生成を処理する次の方法を思いつきました (JPA プロバイダーとして Hibernate を使用していると仮定します)。

  • ddl スキーマ生成を使用して、DB スキーマを生成できます。このオプションを使用すると、Web サーバーの起動中にスキーマが作成/更新されます。このメソッドを使用する場合、onDelete オプションがカスケードに設定されていることを確認するために、OnDelete アノテーションを使用できます。これは、OneToOne 関係では問題なく機能しましたが ( Angel Villalainのおかげで)、何らかの理由で OneToMany 関係では機能しませんでした。このギャップを回避するために、Spring のResourceDatabasePopulatorを使用しました。

ここに画像の説明を入力

db-additions.sql ファイルには、DB を適合させるクエリが含まれています。私の場合は、Ondelete Cascade を作成します。例えば:

ALTER TABLE `buysmartdb`.`users_providers` DROP FOREIGN KEY `FKB4152EEBBF9006F5` ;
ALTER TABLE `buysmartdb`.`users_providers` 
  ADD CONSTRAINT `FKB4152EEBBF9006F5`
  FOREIGN KEY (`User_Id` )
  REFERENCES `buysmartdb`.`users` (`User_Id` )
  ON DELETE CASCADE
  ON UPDATE CASCADE;

ResourceDatabasePopulator によってトリガーされるスクリプトは、スキーマが Hibernate ddl によって生成された後に適用されることに注意してください。これは良いことです。最終結果のせいで、それが保証されていることを本当に確認できなかったことを私は知っています。

  • 2 番目の方法は、コンパイル時に maven を使用してスキーマを生成することです。これあれなど、いくつかの方法があります。

これが誰かを助けることを願っています..

于 2013-01-02T14:12:31.010 に答える