Spring数据-根据之前的插入插入数据 [英] Spring data - insert data depending on previous insert

查看:32
本文介绍了Spring数据-根据之前的插入插入数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将数据保存到 2 个表中(一个实体和一个关联表).我只是使用实体存储库中的 save() 方法保存我的实体.然后,为了表演,我需要在 native sql 的关联表中插入行.这些行对我之前保存的实体有一个引用.问题出现在这里:我收到一个关于外键的完整性约束异常.在第二个查询中不知道首先保存的实体.

这是我的代码:

回购:

public interface DistributionRepository extends JpaRepository, QueryDslPredicateExecutor{@修改@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 servicesIds);}

服务:

@Service公共类 DistributionServiceImpl 实现 IDistributionService {@注入私有 DistributionRepository distributionRepository;@覆盖@交易公共分发资源分发(最终分发资源分发){//1.实体创建和保存分配创建 = 新分配();最终日期分布日期 = 新日期();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.关联表最终集<长>serviceIds = new HashSet();for (final ServiceResource sr : distribution.getServices()) {serviceIds.add(sr.getTechId());}//这里的例外distributionRepository.insertDistributionPerimeter(created.getId(), serviceIds);}}

这 2 个查询似乎在不同的事务中,而我设置了 @Transactionnal 注释.我还尝试使用 entityManager.createNativeQuery() 执行我的第二个查询并得到相同的结果...

解决方案

在执行原生查询之前调用 entityManager.flush() 或使用 saveAndFlush 代替.>

我建议使用您的具体情况

created = distributionRepository.saveAndFlush(created);

重要提示:您的本机"查询必须使用相同的事务!(或者你现在需要一个事务隔离级别)

<小时>

你还写道:

<块引用>

我真的不明白为什么默认情况下不进行刷新操作

刷新由 Hibernate 处理(可以配置,默认为自动").这意味着休眠将在任何时间点刷新数据.但总是在您提交事务或通过 HIBERNATE 执行其他 SQL 语句之前.- 所以通常这没问题,但在你的情况下,你用你的原生查询绕过了休眠,所以休眠不会知道这个语句,因此它不会刷新它的数据.

另见我的这个答案:https://stackoverflow.com/a/17889017/280244关于这个话题

I need to save data into 2 tables (an entity and an association table). I simply save my entity with the save() method from my entity repository. Then, for performances, I need to insert rows into an association table in native sql. The rows have a reference on the entity I saved before. The issue comes here : I get an integrity constraint exception concerning a Foreign Key. The entity saved first isn't known in this second query.

Here is my code :

The repo :

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

The service :

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

The 2 queries seem to be in different transactions whereas I set the @Transactionnal annotation. I also tried to execute my second query with an entityManager.createNativeQuery() and got the same result...

解决方案

Invoke entityManager.flush() before you execute your native queries or use saveAndFlush instead.

I your specific case I would recommend to use

created = distributionRepository.saveAndFlush(created);

Important: your "native" queries must use the same transaction! (or you need a now transaction isolation level)


you also wrote:

I don't really understand why the flush action is not done by default

Flushing is handled by Hibernate (it can been configured, default is "auto"). This mean that hibernate will flush the data at any point in time. But always before you commit the transaction or execute an other SQL statement VIA HIBERNATE. - So normally this is no problem, but in your case, you bypass hibernate with your native query, so hibernate will not know about this statement and therefore it will not flush its data.

See also this answer of mine: https://stackoverflow.com/a/17889017/280244 about this topic

这篇关于Spring数据-根据之前的插入插入数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆