JPA/hibernate 生成了错误的 SQL 语句
JPA/hibernate is generating the wrong SQL statement
我的 JpaRepository
生成了错误的 SQL。它只更新商店而不更新实体的其余部分。仔细观察后,我注意到查询说 update shop set
与 campaign
实体无关,其中 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
语句。
我的 JpaRepository
生成了错误的 SQL。它只更新商店而不更新实体的其余部分。仔细观察后,我注意到查询说 update shop set
与 campaign
实体无关,其中 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
语句。