JPA / hibernate生成错误的SQL语句

时间:2018-04-30 12:18:52

标签: spring-boot jpa spring-data spring-data-jpa jpa-2.1

我的JpaRepository生成了错误的SQL。它只更新商店而不是实体的其余部分。仔细观察后,我发现该查询对update shop set实体campaign内部的shop内没有任何说明。

Inside Campaign有一家商店:

 @JoinColumn(name = "SHOP_ID", referencedColumnName = "SHOP_ID", nullable = false)
    @ManyToOne(cascade = CascadeType.ALL)
    private Shop shop;

在店内我有一套:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "shop")
private Set<Campaign> campaignSet;

使用saveAndFlush -

生成的查询
update shop set created_at=?, currency=?, currency_iso_code=?, default_delivery_cost=?, delivery_cost_erp_number=?, description=?, default_language_id=?, modified_at=?, sales_organisation_id=?, code=?, valid_from=?, valid_till=? where shop_id=?

我希望保存整个广告系列,老实说我并不关心更新商店,因为在更新广告系列时我永远不会这样做。

方法更新:

@Override
@Modifying
@Transactional
public CampaignDto update(CampaignDto campaignDto) throws RequestNotFoundException {
    //TODO: compare objects to see if there is a change

    Campaign campaign = mapper.mapReverse(campaignDto);

    if (campaign.getCampaignId() != null) {
        campaign = campaignRepository.getOne(campaign.getCampaignId());

        if (campaign.getCampaignId() == null) {
            throw new RequestNotFoundException(
                    String.format("Campaign %s is not found", campaign.getKey().toString()));
        }
    }

    Shop shop = shopRepository.getOne(campaignDto.getShopId());

    if (shop.getShopId() > 0 && shop.getShopId() != null) {
        shop.setCode(campaignDto.getShopCode());
        shop.setCurrency(campaignDto.getShopCurrency());
        shop.setCurrencyIsoCode(campaignDto.getShopCurrencyIso());
        shop.setValidFrom(campaignDto.getValidFrom());
        shop.setValidTill(campaignDto.getValidTill());
        shop.setCreatedAt(OffsetDateTime.now());
        shop.setSalesOrganisationId(campaignDto.getSalesOrganisationId());
    } else {
        throw new IllegalArgumentException("Must declare an existing shop to update a campaign.");
    }

    Language language = languageRepository.getOne(campaignDto.getLanguageId());
    if (!StringUtils.isEmpty(language.getLanguageId()) && language.getLanguageId() != null) {
        language.setLanguageId(campaignDto.getLanguageId());
        shop.setLanguage(language);
    } else {
        throw new IllegalArgumentException("Must declare an existing language to update a campaign.");
    }

    campaign.setShop(shop);
    CampaignDto updatedCampaign = mapper.map(campaign);
    campaignRepository.saveAndFlush(campaign);

    return updatedCampaign;
}

1 个答案:

答案 0 :(得分:0)

  

老实说,我不关心更新商店,因为在更新广告系列时我永远不会这样做

为什么CascadeType.ALL呢?你永远不应该永远使用CascadeType.ALL与多对一关联。这是因为CascadeType.MERGE很少有意义(你实际上是在乞求像你描述的那样的意外副作用),而CascadeType.REMOVE只是纯粹的邪恶(通过删除孩子,你删除了父母,反过来导致其他所有孩子被删除,因为CascadeType.ALL上有另一个Shop.campaigns

另外,如果您在保存Shop时从不想更新Campaign,以下代码的目的是什么?

if (shop.getShopId() > 0 && shop.getShopId() != null) {
    shop.setCode(campaignDto.getShopCode());
    shop.setCurrency(campaignDto.getShopCurrency());
    shop.setCurrencyIsoCode(campaignDto.getShopCurrencyIso());
    shop.setValidFrom(campaignDto.getValidFrom());
    shop.setValidTill(campaignDto.getValidTill());
    shop.setCreatedAt(OffsetDateTime.now());
    shop.setSalesOrganisationId(campaignDto.getSalesOrganisationId());
}

如果您确实不想更新Shop,请删除该部分。作为旁注,您可能希望交换if子句中的条件。

最后,如果您没有看到CAMPAIGN表的更新,可能是因为Campaign实体没有实际更改。通常,Hibernate将检索当前状态并将其与更新的Entity进行比较,以避免不必要的UPDATE语句。