4

休止状態で spring-data JPA を使用しています。継承と関係のマッピングを正しく機能させるのが非常に困難です。

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name="compound")
@DiscriminatorColumn(name="compound_type")
@DiscriminatorOptions(force=true)
public abstract class Compound<T extends Containable> {

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.compound",
        cascade = CascadeType.ALL, orphanRemoval = true)
    @LazyCollection(LazyCollectionOption.FALSE)     
    private List<CompoundComposition> compositions = new ArrayList<>(); 

    @OneToMany(fetch = FetchType.EAGER, mappedBy="compound",
        targetEntity=Containable.class, cascade = CascadeType.ALL) 
    @LazyCollection(LazyCollectionOption.FALSE)     
    private Set<T> containables = new HashSet<T>();

}

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name="containable")
@DiscriminatorColumn(name="containable_type")
@DiscriminatorOptions(force=true)
public abstract class Containable<T extends Compound> {     

    @ManyToOne(optional=true, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private T compound;
}

AbstractCompound の特定の実装は、Containable の 1 つの特定の実装にのみ関連付けることができます (逆も同様です)。これにより、次の実装が行われます。

@Entity 
@DiscriminatorValue("TestCompound") 
public class TestCompound extends AbstractCompound<TestContainable> {
}

@Entity 
@DiscriminatorValue("RegistrationCompound")
public class RegistrationCompound extends AbstractCompound<Batch> {

    @Column(name = "reg_number", unique = true)
    private String regNumber;
}

@Entity 
@DiscriminatorValue("TestContainable")  
public class TestContainable extends Containable<TestCompound> {
}

@Entity 
@DiscriminatorValue("Batch")    
public class Batch extends Containable<RegistrationCompound>{

    @Column(name = "batch_number")
    private Integer batchNumber;
}

私はすべての継承戦略をいじりましたが、複合階層の単一テーブルは、少なくとも部分的に機能する唯一のものです。JOINED または table _per_class の場合、hibernate は一貫性がなく間違ったものを作成します!!! 外部キー、つまり test_containable から registration_compound へ (ただし、Batch から test_compound へではありません。ここでは、registration_compound のみに正しくマップされます)。

収容可能な側では、私がどの戦略を使用するかは問題ではないようです。

私のテストの実際の問題に移ります。特定のテスト クラス。には 3 つのテストがあります。すべて「TestCompound」インスタンスの特定の検索を行っています。問題は、これら 3 つのテスト ケースのうち最初に実行されたものが常に成功し、残りの 2 つが常に失敗することです。実行される順序はランダムのようです (JUnit + @RunWith(SpringJUnit4ClassRunner.class))。これは、最初に実行されたテストであれば、いずれのテストもパスすることを意味します。

失敗したテストは、次の例外をスローします。

org.hibernate.WrongClassException: Object with id: 1000 was not of the specified
    subclass: RegistrationCompound (loaded object was of wrong class class TestCompound)

最初のテストの場合、Containables を取得するための正しい選択に続いて休止状態の問題が発生する

Hibernate: select containabl0_.compound_id as compound8_1_1_, containabl0_.id as id0_1_, 
containabl0_.id as id0_0_, containabl0_.created as created0_0_, 
containabl0_.created_by as created4_0_0_, containabl0_.last_modified as last5_0_0_, 
containabl0_.last_modified_by as last6_0_0_, containabl0_.compound_id as compound8_0_0_, 
containabl0_.batch_number as batch7_0_0_, containabl0_.containable_type as containa1_0_0_ 
from containable containabl0_ where  containabl0_.containable_type in ('Batch', 'TestContainable') 
and containabl0_.compound_id=?

List<CompoundComposition> compositionsが別の select ステートメントで選択されています。したがって、これらは合計 3 つのステートメントです: Get Compound、Get Containables、Get Composition です。

2 番目と 3 番目のテストでは、containables をフェッチするための SQL がコンポジションをフェッチするための SQL とマージされ、TestCompound の代わりに RegistrationCompound を選択しようとするような方法で構築されます。

registrati1_.reg_number as reg10_1_0_, 

reg_number は、RegistrationCompound のみのプロパティです。どちらの場合も、実際の化合物を正しく選択する最初の select ステートメントには、where 句に次のものが含まれています。

testcompou0_.compound_type='TestCompound'

したがって、これは非常に紛らわしいです。テストが実行される順序に依存するのはなぜですか? 一体なぜ、RegistrationCompound を選択しようとするのでしょうか?

3 つのテストの中で最も簡単なテストを次に示します。

@Test
@Transactional
public void testFindByCompositionPkStructureId() {
    System.out.println("findByCompositionPkStructureId");

    Long structureId = 1000L;

    TestCompound compound = new TestCompound();
    compound.setId(1000L);
    compound.setCas("9999-99-9");
    compound.setCompoundName("Test Compound");

    List<TestCompound> result = 
        testCompoundRepository.findByCompositionsPkStructureId(structureId);
    assertEquals(compound, result.get(0));
}

このテストが 2 番目または 3 番目に実行されると、間違ったクラス例外が発生します!!! ここで一体何が起こっているのか誰にも分かりませんか?解決?

4

1 に答える 1

7

問題はマッピングの1つでした:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name="containable")
@DiscriminatorColumn(name="containable_type")
@DiscriminatorOptions(force=true)
public abstract class Containable<T extends Compound> {     

    @ManyToOne(optional=true, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private T compound;
}

このマッピングにはターゲットエンティティがありません。正解は

@ManyToOne(optional=true, fetch = FetchType.EAGER, cascade = CascadeType.ALL, targetEntity = Compound.class)

何らかの理由で、休止状態は、ターゲットがRegistrationCompound例外をスローする代わりにあると想定しました。そうでなければ問題を見つけるのは簡単だったでしょうから、かなり迷惑です。しかし、このようにそれはほとんど私を夢中にさせました。

于 2013-02-17T09:01:39.773 に答える