2013-02-11 8 views
2

Я использую 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 (и наоборот). Это приводит к следующему implementaions:

@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 или таблицы _per_class hibernate создает непоследовательную и неправильную !!! внешние ключи, а именно от test_contable to registration_compound (но не от Batch to test_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 выбирается другой выбор заявление. Таким образом, у них есть в общей сложности 3 заявления: Получите состав, получите сдерживающие способности, получите композиции.

Для второго и третьего теста SQL для извлечения сдерживаемых объектов объединен с включенным для извлечения композиций, и он построен таким образом, что он пытается выбрать RegistrationCompound вместо TestCompound, в качестве примера он содержит

registrati1_.reg_number as reg10_1_0_, 

и reg_number является собственностью RegistrationCompound. В обоих случаях первый оператор выбора, который выбирает фактическое соединение правильно содержит следующее где положение:

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)); 
} 

Если этот тест запускается как второй или третий я получаю исключение неправильный класс !!! Кто-нибудь знает, что здесь происходит? Решение?

+0

Ваши тесты Откат? – willome

+0

Не те, которые ничего не меняют. однако оказывается, что удаление @Cache Annotation от всех entites решило эту проблему. Однако теперь я сталкиваюсь с новым, но очень похожим. –

ответ

5

Вопрос был один из отображений:

@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 вместо того, чтобы выбросить исключение. Довольно раздражает, потому что иначе было бы легко найти проблему. Но, похоже, это почти сводило меня с ума.

Смежные вопросы