在hibernate中保存集合的元素

时间:2016-08-09 10:11:16

标签: java hibernate cascade cascading-deletes

我上课了ResponsedAd:

@Entity
@Table(name = "RESPONSED_AD_TEST")
@NamedQueries({
 @NamedQuery(name = "responsedAdsByAd",query="from ResponsedAd where ad = :ad")
})
@Component
public class ResponsedAd {

@Id
@SequenceGenerator(name = "standard", initialValue = 1)
@GeneratedValue(generator = "standard", strategy = GenerationType.SEQUENCE)
private long id;

@ManyToOne(fetch = FetchType.EAGER)
@Cascade(CascadeType.REMOVE)
@JoinColumn(name = "AD",nullable = false)
private Ad ad;

@Column(nullable = false)
private LocalDateTime dateTimeOfResponse;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "CLIENT",nullable = false)
private Client client;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "TRANSLATOR",nullable = false)
private Translator translator;

@Column(nullable = false)
@Enumerated(EnumType.STRING)
private ResponsedAdStatus status;


public ResponsedAd(){}

他与班级有@ManyToOne关系:客户,广告,翻译

客户端:

    @Entity
@NamedQueries({
    @NamedQuery(name =  "clientByEmail",
                query = "from Client client where client.email = :email")
})
@Table(name = "CLIENT_TEST")
@PrimaryKeyJoinColumn(name= "client_id")
public class Client extends User{

    /**
     * Version of this class in production 
     */
    private static final long serialVersionUID = 1L;

    @OneToMany(fetch = FetchType.EAGER,orphanRemoval = true,mappedBy = "client")
    @Cascade(CascadeType.ALL)
    public List<Ad> ads = new ArrayList<>();

    @OneToMany(fetch = FetchType.EAGER,orphanRemoval = true,mappedBy = "client")
    @Cascade(CascadeType.ALL)
    private List<ResponsedAd> responsedAds = new ArrayList<>();

    public Client(){}

    public static long getSerialversionuid() {
        return serialVersionUID;
    }
    public List<Ad> getAds() {
        return ads;
    }

    public void setAds(List<Ad> ads) {
        this.ads = ads;
    }

    public void addAd(Ad ad){
        ads.add(ad);
        ad.setClient(this);
    }

    public void removeAd(Ad ad){
        ads.remove(ad);
        ad.setClient(null);
    }

    public List<ResponsedAd> getResponsedAds() {
        return responsedAds;
    }

    public void addResponsedAd(ResponsedAd responsedAd){
        responsedAds.add(responsedAd);
        responsedAd.setClient(this);
    }

    public void removeResponsedAd(ResponsedAd responsedAd){
        responsedAds.remove(responsedAd);
        responsedAd.setClient(null);
    }

广告:

    @Entity
@NamedQueries({
    @NamedQuery(name =  "getAllAds",
            query = "from Ad"),
    @NamedQuery(name =  "deleteById",
    query = "delete from Ad where id = :id")
})
@FieldNotMatch(first = "initLanguage",second = "resultLanguage", message = "Languages must be different")
@Table(name = "AD_TEST")
public class Ad  implements Serializable{

    /**
     * Version of this class in production 
     */
    private static final long serialVersionUID = 1L;

    @Id
    @SequenceGenerator(name = "standard", initialValue = 1)
    @GeneratedValue(generator = "standard", strategy =GenerationType.SEQUENCE)
    @Column(name = "AD_ID")
    private long id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "CLIENT",nullable = false)
    private Client client;

    @NotBlank
    @Column(name = "AD_NAME", nullable = false)
    private String name;

    @NotBlank
    @Column(name = "AD_DESC",nullable = false,length = 1000)
    @Lob
    @Size(min = 0, max = 1000)
    private String description;

    @Column(name = "AD_COUNTRY", nullable = false)
    private String country;

    @Column(name = "AD_CITY", nullable = false)
    private String city;


    /**
     * Добавить проверку валидности даты
     */
    @DateTimeFormat(iso = ISO.DATE,pattern = "dd.MM.yyyy")
    @Column(name = "AD_END_DATE",nullable = false)
    private LocalDate endDate;

    @Column(name = "AD_INIT_LANGUAGE",nullable = false)
    @Enumerated(EnumType.STRING)
    private Language initLanguage;

    @Column(name = "AD_RESULT_LANGUAGE",nullable = false)
    @Enumerated(EnumType.STRING)
    private Language resultLanguage;

    @Column(name = "AD_TRANSLATE_TYPE",nullable = false)
    @Enumerated(EnumType.STRING)
    private TranslateType translateType;

    @Lob
    @Column(name = "AD_FILE")
    private byte[] file;

    @Column(name = "AD_COST",nullable = false,precision = 2)
    private double cost;

    @Column(name = "AD_CURRENCY",nullable = false)
    @Enumerated(EnumType.STRING)
    private Currency currency;

    @Column(name = "AD_PUBLICATIO_DATE_TIME",nullable = false)
    private LocalDateTime publicationDateTime;

    @Column(name = "AD_STATUS",nullable = false)
    @Enumerated(EnumType.STRING)
    private AdStatus status;

    @OneToMany(fetch = FetchType.EAGER,orphanRemoval = true,mappedBy = "ad")
    @Cascade(CascadeType.ALL)
    private List<ResponsedAd> responsedAds = new ArrayList<>();

    public Ad(){}

这是保存ResponsedAd的方法:

@Override
    public void saveResponsedAd(String email,long adId) throws NonExistedAdException {
        Ad ad = adDao.get(adId);
        if(ad == null){
            throw new NonExistedAdException();
        }

        ResponsedAd responsedAd = new ResponsedAd();

        Translator translator = translatorDao.getTranslatorByEmail(email);
        Client client = ad.getClient();

        translator.addResponsedAd(responsedAd);
        client.addResponsedAd(responsedAd);
        ad.addResponsedAd(responsedAd);

        responsedAd.setStatus(ResponsedAdStatus.SENDED);
        responsedAd.setDateTimeOfResponse(LocalDateTime.now());

        responsedAdDao.save(responsedAd);

    }

保存后,我在Responsed_Ad_Test表中有适当的行。

当我想要删除广告时我有一个错误,我的客户端对象来自下面的方法有3个相同的ResponsedAd,我有异常:已删除的对象将通过级联重新保存(从关联中删除已删除的对象)。

我不知道为什么我的客户端重复了ResponsedAd对象,而保存我的客户端对象只有1个ResponsedAd对象

@Override
    public void deleteById(long id) throws NonExistedAdException,UnacceptableActionForAcceptedAd{
        Ad ad = get(id);
        if(ad.getStatus().equals(AdStatus.ACCEPTED)){
            throw new UnacceptableActionForAcceptedAd();
        }
        List<ResponsedAd> list = new ArrayList<>(ad.getResponsedAds());
        list.stream().forEach(rad->{
            Translator translator = rad.getTranslator();
            Client client = rad.getClient();
            translator.removeResponsedAd(rad);
            ad.removeResponsedAd(rad);
            client.removeResponsedAd(rad);
        });

        Client client = ad.getClient();
        client.removeAd(ad);
    }

我知道问题在于保存ResponsedAd对象,但我无法理解为客户端创建几个相同的ResponsedAd对象。 请帮助:)

1 个答案:

答案 0 :(得分:0)

问题在于集合的急切初始化。因为这个初始化加载了重复的对象。我将FetchType从EAGER更改为LAZY,问题解决了)