2013-11-22 2 views
0

Чтобы изначально заполнить базу данных данными, я создал экземпляры сущностей и написал класс обслуживания, который должен сохранить их в базе данных.Как сохранить исходные данные с помощью JpaRepository

В очень упрощенном виде, моя модель состоит из трех классов A, B и C. экземпляры классов А и В обоих эталонных (одни и те же) экземпляры C (аннотированные с @ManyToOne):

a1 -> c1 
a2 -> c2 
a3 -> c1 

b1 -> c1 
b2 -> c2 

Для A и BI используйте JpaRepositories для настойчивости.

Тогда я пытаюсь сохранить экземпляры я создал программно:

@Transactional 
public void save(A a1, A a2, A a3, B b1, B b2) { 
    aRepo.save(a1); 
    aRepo.save(a2); 
    aRepo.save(a3); 

    bRepo.save(b1); 
    bRepo.save(b2); 
} 

я получаю исключение («отдельно стоящий объект передается упорствовать: C») в третьей строке, так как экземпляр c1 спасся уже в первая строка.

Как я могу избежать этого? Я думал, что маркировка моего метода сохранения в моем сервисе с @Transactional будет достаточной, но, очевидно, это не так.

Конечно, я мог бы просто написать

aRepo.save(Arrays.asList(a1, a2, a3)); 
bRepo.save(Arrays.asList(b1, b2)); 

но сдвигает только моя проблема, как исключение, то происходит во второй строке, когда b1, который ссылается на уже сохраненный c1 должен получить спасение.

Как сохранить структуры данных, созданные мной одним способом, не получая это исключение?

Вот остальная часть кода:

@Entity 
public class A { 

    @Id 
    @GeneratedValue 
    @Access(AccessType.FIELD) 
    private Long id; 

    @ManyToOne(cascade = CascadeType.ALL) 
    @Access(AccessType.FIELD) 
    private C c; 

    public A(C c) { 
     this.c = c; 
    } 

    public C getC() { 
     return c; 
    } 
} 

класса B выглядит точно так же, класс C содержит только параметр ID.

экземпляры создаются в тесте:

public class DBTest extends AbstractH2TestCase { 

    @Test 
    public void testDataStorage() { 

     final AbstractApplicationContext context = new AnnotationConfigApplicationContext(DBTest.class); 

     try { 
      final PersistService persistService = context.getBean(PersistService.class); 

      C c1 = new C(); 
      C c2 = new C(); 

      A a1 = new A(c1); 
      A a2 = new A(c2); 
      A a3 = new A(c1); 

      B b1 = new B(c1); 
      B b2 = new B(c2); 

      persistService.save(b1, b2, a1, a2, a3); 

     } finally { 
      context.close(); 
     } 
    } 
} 

Суперкласс для теста я нашел где-то в Интернете, и модифицировали его немного:

@Configuration 
@ComponentScan(basePackageClasses = A.class) 
@EnableJpaRepositories 
public class AbstractH2TestCase { 

    public AbstractH2TestCase() { 
     super(); 
    } 

    @Bean 
    public DataSource dataSource() { 
     return new EmbeddedDatabaseBuilder().setType(H2).build(); 
    } 

    @Bean 
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, 
      JpaVendorAdapter jpaVendorAdapter) { 

     final LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean(); 

     lef.setDataSource(dataSource); 
     lef.setJpaVendorAdapter(jpaVendorAdapter); 

     final String thisPackageAndSubpackages = this.getClass().getPackage().getName(); 
     lef.setPackagesToScan(thisPackageAndSubpackages); 

     return lef; 
    } 

    @Bean 
    public JpaVendorAdapter jpaVendorAdapter() { 

     final HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter(); 

     hibernateJpaVendorAdapter.setShowSql(false); 
     hibernateJpaVendorAdapter.setGenerateDdl(true); 
     hibernateJpaVendorAdapter.setDatabase(Database.H2); 

     return hibernateJpaVendorAdapter; 
    } 

    @Bean 
    public PlatformTransactionManager transactionManager() { 
     return new JpaTransactionManager(); 
    } 

} 

Если вы хотите бегущую версию кода - Я проверил его здесь:

https://github.com/BernhardBln/stackexchange

Это проект maven.

+0

Не могли бы вы показать код, который инициализирует экземпляры А1-3 и c1, c2? – PepperBob

+0

Я добавил его, а также ссылку на github, где я поставил пример для запуска – Bernhard

ответ

1

Вы упускаете

@EnableTransactionManagement 

на вас DBTEST-класса

@EnableTransactionManagement 
    public class DBTest extends AbstractH2TestCase { 
0

Вашего @Transactional аннотации бесполезно, потому что вы не используете контейнер (например, J2EE или Spring) на самом деле понять, что этот метод должен быть запущен в одной транзакции, поэтому каждый вызов save() является сделкой, и именно поэтому вы» чтобы получить отдельную сущность.

Попробуйте использовать пружину как в this example или the docs.

+0

Я думал, что использую контейнер при получении моего сервиса через 'PersistService persistService = context.getBean (...)'? И в абстрактном супер классе моего тестового примера конфигурация с помощью аннотаций кажется такой же, как в вашем примере xml? – Bernhard

+0

При создании AnnotationConfigApplicationContext вы должны передать классы компонентов, для которых вы хотите, чтобы аннотации были отсканированы. Вы проходите только DBTest.class. Попробуйте передать класс, в котором вы определяете метод save(). –

+0

Я аннотировал суперкласс класса DBTest с помощью '@ComponentScan (basePackageClasses = A.class)', которого было достаточно, поскольку все классы (в этом примере) живут в одном пакете. Фактическая проблема заключалась в том, что управление транзакциями не было активировано, как указал PepperBob в своем ответе. После аннотирования моего DBTest с помощью '@ EnableTransactionManagement' все работало, как ожидалось. Я обновил свой пример проекта на github, вы можете посмотреть, если хотите. – Bernhard

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