Emirhan Ay
Emirhan Ay

Reputation: 53

Confusion with spring @ManyToMany

i have product and campaign entity with ManyToMany relationship. When I define a campaign for the product, I add something like this to the product_campaigns table in the db. For example:

product_campaigns : product_id : 1 campaign_id : 1

It means that campaign with 1 id is defined for the product with 1 id. When I delete the campaign number 1, I want the lines with the number 1 campaign defined in the product_campaigns table to be deleted. But now when i delete the campaign number 1 ,it both deletes the product_campaigns row and deletes the related product object in the product table . What am i wrong ? Thx.

@Getter
@Setter
@Entity
public class Product extends BaseExtendedModel {


    private String name;
    private BigDecimal price;
    private UUID barcode;
    private String image;

    @ManyToOne
    private Brand brand;
    @ManyToOne
    private Category category;
    @ManyToOne
    private Seller seller;

    private int stock;

    private BigDecimal taxRate;

    @ManyToMany
    @JoinTable(name = "PRODUCT_CAMPAIGN", joinColumns = { @JoinColumn(name = "product_id") }, inverseJoinColumns = { @JoinColumn(name = "campaign_id") })
    private Set<Campaign> campaigns = new HashSet<>();

}
@Entity
@Getter
@Setter
public class Campaign extends BaseModel{

    private BigDecimal discountRate;
    private BigDecimal discountPrice;
    private String name;
    private String description;
    private Date startDate;
    private Date endDate;

    @ManyToMany(mappedBy = "campaigns",cascade = CascadeType.ALL)
    private Set<Product> productSet = new HashSet<>();

}
@Component
@RequiredArgsConstructor
public class CampaignServiceImpl implements CampaignService{
    private final CampaignRepository campaignRepository;
    private final CampaignConverter campaignConverter;
    @Override
    public void create(CreateCampaignRequestDTO createCampaignRequestDTO) {
        Campaign campaign = campaignConverter.toCampaign(createCampaignRequestDTO);
        campaignRepository.save(campaign);
    }
    public Campaign getCampaign(Long campaignId){
        return campaignRepository.findById(campaignId).orElseThrow(
                () -> new BusinessServiceOperationException.CampaignNotFoundException("Campaign not found")
        );
    }

    @Override
    public void delete(Long campaignId) {
        Campaign campaign = getCampaign(campaignId);
        campaignRepository.delete(campaign);
    }
}

Upvotes: 0

Views: 311

Answers (1)

Igor Flakiewicz
Igor Flakiewicz

Reputation: 793

When deleting you have to pay attention to your cascade types. CascadeType.ALL includes REMOVE so you're telling spring data to delete all the items in the productSet.

What you want is CascadeType.PERSIST, also add the @JoinTable annotation.

@Entity
public class Campaign extends BaseModel {

    // your other code

    @ManyToMany(mappedBy = "campaigns", cascade = CascadeType.PERSIST)
    @JoinTable(
        name = "PRODUCT_CAMPAIGN", 
        joinColumns = @JoinColumn(name = "campaign_id"), 
        inverseJoinColumns = @JoinColumn(name = "product_id"))
    private Set<Product> productSet = new HashSet<>();

}

Link to documentation: https://openjpa.apache.org/builds/2.4.0/apache-openjpa/docs/jpa_overview_meta_field.html#jpa_overview_meta_cascade

Upvotes: 1

Related Questions