2017-02-08 15 views
0

私はあなたにうんざりさせる奇妙な問題があります。私は奇妙なSpring/Hibernateアプリケーションを持っています。これはデータベースを次のように管理することを目的としています(私はいくつかのことを単純化していますので、ソースコードに少し異なるテーブル/カラムがあることを混同しないでください)。Hibernate:親削除の子コレクションを削除しないでください

active_proxy_view table: 
id  | entity 
<uuid> | <string containing json> 

archive_proxy_view table: 
id  | entity 
<uuid> | <string containing json> 

track_reference table: 
ref_type | ref_id | track_domain | track_type | track_id | 
'proxy' | <uuid> | 'example.com' | 'customer' | '123' | 

2つのテーブルを保持することは必須です - 私はすべての時間履歴/統計クエリとビジネス値クエリを現在アクティブなものに対してのみ持つ必要があるので、アクティブなプロキシを厳密に設定する必要があります。私はそのようなクエリを行うことができますので、track_referenceテーブルを検索するために使用されます。

​​

(それはない100%正しいことも、私はしばらくの間で生のSQLの経験を持っていない)

そして、

  • 両方active_proxy_viewarchive_proxy_viewエンティティが一つのクラスから継承され@OneToMany関係0を指定しています。ここでの問題ですn track_reference実体;参照
  • track_referenceを追跡するに結ば多くの企業があるので@ManyToOne使用量が個別に管理(これはあまりにも必須です)さを取り除くために休止状態私はtrack_referenceテーブルとは別にビューを管理する必要がありますが、私が言うたび
  • 、実際には不可能ですエンティティはactive_proxy_viewテーブルから、track_referenceのエンティティも削除します。デフォルトで空白のカスケード注釈値を再生しても、(私が理解するように、それは子レコードを親と一緒に削除しないでください)。しかし、私は何かを逃した可能性があります。私は春の4.3.2を通じて休止状態5.2.3.Finalを使用してい

    55 Query  delete from tracking_reference where referenced_entity_id='13c6b55c-f9b7-4de7-8bd4-958d487e461c' and referenced_entity_type='proxy' and tracked_entity_type='agent' 
    55 Query  delete from tracking_reference where referenced_entity_id='13c6b55c-f9b7-4de7-8bd4-958d487e461c' and referenced_entity_type='proxy' and tracked_entity_type='lead' 
    55 Query  delete from tracking_reference where referenced_entity_id='13c6b55c-f9b7-4de7-8bd4-958d487e461c' and referenced_entity_type='proxy' and tracked_entity_type='source' 
    53 Query  DELETE FROM `tracking_reference` WHERE `referenced_entity_type` = 'proxy' AND referenced_entity_id = '13c6b55c-f9b7-4de7-8bd4-958d487e461c' AND 1 = 0 
    
  • は、私はまた、私はまだ一般的なログに定期的に削除を確認することができ、カスタム @SQLDeleteAllを使用して、全体のことをハックすることができませんでした。リリース/スプリングデータJPA 1.10.2.RELEASE

TL; DR

親が削除されたときにHibernateが関連エンティティを削除するのを防ぐにはどうすればいいですか?あなたが@JoinColumnを削除した場合、あなたはこの問題を持っていないはず

@NoRepositoryBean 
public interface SuperRepository<E, ID extends Serializable> extends PagingAndSortingRepository<E, ID>, 
     JpaSpecificationExecutor<E> { 
} 

public interface ActiveProxyViewRepository extends SuperRepository<ActiveProxyViewEntry, String> {} 

// the call for deletion 
public CompletableFuture<Void> delete(ID id) { 
    ... 
    descriptor.getRepository().delete(descriptor.getIdentifierConverter().convert(id)); 
    ... 
} 
// which is equal to 
... 
ActiveProxyViewRepository repository = descriptor.getRepository(); 
String uuidAsString = descriptor.getIdentifierConverter().convert(id); 
repository.delete(uuidAsString); 
... 
+0

エンティティを削除する方法を示すコードを含めてください。 – Naros

+0

@Naros出来ましたが、それほど助けになるとは思えませんでした – Etki

答えて

0

@Entity 
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
public class ProxyViewEntryTemplate { 

    @Id 
    @NotNull 
    @Column(nullable = false) 
    private String id; 

    @NotNull 
    @Column 
    private String entity; 

    // some other columns 

    @OneToMany 
    @JoinColumn(name = TrackRef.REFERENCE_ID_COLUMN_NAME) // 'reference_entity_id` 
    @Where(clause = ProxyView.TRACK_WHERE_JOIN_CLAUSE) // `referenced_entity_type` = 'proxy' 
    @SQLDeleteAll(sql = ProxyView.TRACK_DELETE_ALL_QUERY) // DELETE FROM `tracking_reference` WHERE `referenced_entity_type` = 'proxy' AND referenced_entity_id = ? AND 1 = 0 
    private Collection<TrackingReference> track = new ArrayList<>(); 

    // setters, getters, hashCode, equals 
} 

@Entity 
@Table(name = "active_proxy") 
public class ActiveProxyViewEntry extends ProxyViewEntryTemplate {} 


@Entity 
@Table(name = "tracking_reference") 
@IdClass(TrackingReferenceId.class) 
public class TrackingReference { 

    @Id 
    @Column(name = "tracked_entity_type", nullable = false) 
    @NotNull 
    private String trackedType; 

    @Id 
    @Column(name = "tracked_entity_domain", nullable = false) 
    private String trackedDomain; 

    @Id 
    @Column(name = "tracked_entity_id", nullable = false) 
    private String trackedId; 

    @Id 
    @Column(name = "referenced_entity_type", nullable = false) 
    @NotNull 
    private String referencedType; 

    @Id 
    @Column(name = "referenced_entity_id", nullable = false) 
    @NotNull 
    private String referencedId; 

    // setters, getters, hashCode, equals 
} 

全部が春JPAリポジトリを通じて管理されます。

エンティティのためのソースコードは次のようになります。

あなたが@JoinColumnを維持する必要がある場合は、自動的に注釈を変更することにより、持続性プロバイダによって適用されます外部キー制約の要件を削除する必要があります。

@JoinColumn(
    name = "yourName" 
    foreignKey = @Foreignkey(value = ConstraintMode.NO_CONSTRAINT) 
) 

あなたはその後、削除することができるはず追跡参照を強制的に削除することなくビューエンティティを削除します。

+0

悲しいことに、外来キーの微調整は機能しませんでした。 remove-join-columnのアプローチを試したい場合、私の選択肢は何ですか?私は、Criteria APIを使用して質問に指定されたようなクエリーを作成していますが、正しく理解/覚えていれば、「@ JoinColumn」がプロジェクトに導入され、Criteria API経由での結合が可能になりました。 – Etki

0

これは、足のシナリオで典型的なシュートであることが判明しました。

追跡参照はかなり洗練された方法で更新された:参照の

  • ビルド・コレクションは、データベースに格納する(C1)
  • ロード全て、本参照(C2)
  • ストアC1
  • C2に存在し、C1で参照されていないすべての参照を削除する(collection.removeAllを使用)

そして、それは私の.equalsメソッドがひどく間違って書かれていることが判明し、それぞれのケースでほぼfalseを返しました。そのため、通常はすべての参照がデータベースから削除されていました(問題のログに表示されているクエリ)ので、それは私の責任でした。

私はそれを修正した後、@SQLDeleteAllクエリだけが実行されました。なぜなら私には知られていない理由で、カスケードオプションが設定された場合のように動作しました。私は@OneToMany(updatable = false, insertable = false)を使ってそれを取り除くことができました。それは汚れたハックのように思えるが、私はそれを掘るために十分な時間がない。

私はまだ完全にテストしていませんが、問題を解決することを願っています。

関連する問題