2015-04-23 5 views
4

Мне нужно сохранить данные в 2 таблицы (сущность и таблица ассоциаций). Я просто сохраняю свою сущность с помощью метода save() из моего репозитория объектов. Затем для выступлений мне нужно вставить строки в таблицу ассоциаций в родном sql. Строки содержат ссылку на ранее сохраненную сущность. Проблема возникает здесь: я получаю исключение ограничения целостности относительно внешнего ключа. Первый сохраненный объект не известен в этом втором запросе.Данные о пружинах - данные вставки в зависимости от предыдущей вставки

Вот мой код:

РЭПО:

public interface DistributionRepository extends JpaRepository<Distribution, Long>, QueryDslPredicateExecutor<Distribution> { 

    @Modifying 
    @Query(value = "INSERT INTO DISTRIBUTION_PERIMETER(DISTRIBUTION_ID, SERVICE_ID) SELECT :distId, p.id FROM PERIMETER p " 
     + "WHERE p.id in (:serviceIds) AND p.discriminator = 'SRV' ", nativeQuery = true) 
    void insertDistributionPerimeter(@Param(value = "distId") Long distributionId, @Param(value = "serviceIds") Set<Long> servicesIds); 
} 

Услуга:

@Service 
public class DistributionServiceImpl implements IDistributionService { 

    @Inject 
    private DistributionRepository distributionRepository; 

    @Override 
    @Transactional 
    public DistributionResource distribute(final DistributionResource distribution) { 

     // 1. Entity creation and saving 
     Distribution created = new Distribution(); 
     final Date distributionDate = new Date(); 
     created.setStatus(EnumDistributionStatus.distributing); 
     created.setDistributionDate(distributionDate); 
     created.setDistributor(agentRepository.findOne(distribution.getDistributor().getMatricule())); 
     created.setDocument(documentRepository.findOne(distribution.getDocument().getTechId())); 
     created.setEntity(entityRepository.findOne(distribution.getEntity().getTechId())); 
     created = distributionRepository.save(created); 

     // 2. Association table 
     final Set<Long> serviceIds = new HashSet<Long>(); 
     for (final ServiceResource sr : distribution.getServices()) { 
      serviceIds.add(sr.getTechId()); 
     } 

     // EXCEPTION HERE 
     distributionRepository.insertDistributionPerimeter(created.getId(), serviceIds); 
    } 
} 

В 2 запросов, как представляется, в различных сделок, тогда как я установил @Transactionnal аннотацию. Я также попытался выполнить свой второй запрос с entityManager.createNativeQuery() и получил тот же результат ...

+0

Try [промывке] (http://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data /jpa/repository/JpaRepository.html#flush--) после 'save()' –

+0

Что делать, если вы замените save() на saveAndFlush()? – StanislavL

+0

Также в соответствующей вставке к вторичной таблице вы можете определить триггер. – StanislavL

ответ

3

Вызовите entityManager.flush(), прежде чем выполнять собственные запросы или вместо этого используйте saveAndFlush.

Я ваш конкретный случай, я бы рекомендовал использовать

created = distributionRepository.saveAndFlush(created); 

Важно: ваши «родные» запросы должны использовать ту же самую операцию! (Или вам нужен сейчас уровень изоляции транзакций)


Вы также писали:

Я не понимаю, почему флеш действие не выполняется по умолчанию

Промывка обрабатывается Hibernate (он может быть настроен, по умолчанию «авто»). Это означает, что hibernate будет очищать данные в любой момент времени. Но всегда, прежде чем совершать транзакцию или выполнять другую инструкцию SQL VIA HIBERNATE. - Как правило, это не проблема, но в вашем случае вы обходите спящий режим с помощью собственного запроса, поэтому hibernate не будет знать об этом утверждении и, следовательно, он не будет очищать свои данные.

Смотрите также этот ответ мой: https://stackoverflow.com/a/17889017/280244 об этой теме

+0

Большое спасибо, я не знал об этой возможности. 'saveAndFlush()' отлично работает = D Я действительно не понимаю, почему действие flush не выполняется по умолчанию. Я полагаю, что это для производительности памяти. – Truche