JPA/hibernate 生成了错误的 SQL 语句

JPA/hibernate is generating the wrong SQL statement

我的 JpaRepository 生成了错误的 SQL。它只更新商店而不更新实体的其余部分。仔细观察后,我注意到查询说 update shop setcampaign 实体无关,其中 shop 位于其中。

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

I honestly do not care about updating the shop because I will never do that when updating a campaign

为什么是CascadeType.ALL呢?你不应该,永远 使用 CascadeType.ALL 和 many-to-one 关联。这是因为 CascadeType.MERGE 很少有意义(你本质上是在乞求像你描述的那样的意外副作用),而 CascadeType.REMOVE 只是纯粹的邪恶(通过删除 child,你删除parent,这反过来会导致所有其他 children 被删除,因为你在 Shop.campaigns 上有另一个 CascadeType.ALL)。

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

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 table 的更新,可能是因为 Campaign 实体没有实际更改。通常,Hibernate 会检索当前状态并将其与更新后的 Entity 进行比较,以避免不必要的 UPDATE 语句。