Hibernate: org.hibernate.NonUniqueObjectException: - PullRequest
0 голосов
/ 28 июня 2018

У меня есть 3 разных класса сущностей, т.е. Pashmina, Description, Image, PashminaColour. Здесь Pashmina имеет отношение one-to-many к Description, Image и PashminaColour. Я пытаюсь сохранить все эти объекты одновременно, но там есть какая-то ошибка:

(org.hibernate.HibernateException) org.hibernate.HibernateException: org.hibernate.NonUniqueObjectException: другой объект с таким же значением идентификатора уже был связан с сеансом: [com.nepitc.mshandloomfrabics.entity.Description # 0]

Я использовал следующий код для сохранения

@Override
public void insert(T t) throws HibernateException {
    session = sessionFactory.openSession();
    trans = session.beginTransaction();

    try {
        session.save(t);
        trans.commit();
    } catch(HibernateException ex) {
        trans.rollback();
        throw new HibernateException(ex);
    } finally {
        session.close();   
    }
}

Примечание: Если я сохраняю детали Pashmina только с одним изображением, описанием или цветом пашмины, он позволяет мне вставить, но если я сохраняю Pashmina с несколькими изображениями, цвета или описание пашмины выдают ошибку.

Вот так я реализовал контроллер

@RequestMapping(value = "/add-pashmina", method = RequestMethod.POST)
    public @Async ResponseEntity<String> insertPashmina(@RequestBody Pashmina pashmina) {
        if (pashmina != null) {
            try {
                pashminaService.insert(pashmina);

                pashminaId = pashmina.getPashminaId();

                for (PashminaColour pash : pashmina.getPashminaColor()) {
                    pashminaColorService.insert(new PashminaColour(pash.getColor(), new Pashmina(pashminaId)));
                }

                for (Description desc : pashmina.getDescriptions()) {
                    descriptionService.insert(new Description(desc.getPashminaDescription(), new Pashmina(pashminaId)));
                }

                return new ResponseEntity<>(HttpStatus.OK);

            } catch (HibernateException e) {
                return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
            }
        } else {
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        }
    }

пашмины

public class Pashmina implements Serializable {

    private static final long serialVersionUID = 1L;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "sq_pashmina_id")
    @SequenceGenerator(name = "sq_pashmina_id", sequenceName = "sq_pashmina_id")
    @Column(name = "PASHMINA_ID", unique = true, nullable = false)
    private int pashminaId;

    @Column(name = "PASHMINA_NAME")
    private String pashminaName;

    @Column(name = "PRICE")
    private double price;

    @Column(name = "ADDED_AT", insertable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date addedAt;

    @Column(name = "CATEGORY")
    private String category;

    @Column(name = "ENABLED", insertable = false)
    private Character enabled;

    @OneToMany(mappedBy = "pashmina", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<PashminaColour> pashminaColor;

    @OneToMany(mappedBy = "pashmina", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Image> images;

    @OneToMany(mappedBy = "pashmina", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Description> descriptions;

Изображение

public class Image implements Serializable {

    private static final long serialVersionUID = 1L;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Id

    @Column(name = "IMAGE_ID")
    private int imageId;

    @Column(name = "IMAGE_NAME")
    private String imageName;

    @JoinColumn(name = "PASHMINA_ID", referencedColumnName = "PASHMINA_ID")
    @ManyToOne
    private Pashmina pashmina;

    @Column(name = "PUBLIC_ID")
    private String publicId;

PashminaColour

public class PashminaColour implements Serializable {

    private static final long serialVersionUID = 1L;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Id

    @Column(name = "COLOUR_ID", insertable = false)
    private int colourId;
    @Column(name = "COLOR")
    private String color;

    @JoinColumn(name = "PASHMINA_ID", referencedColumnName = "PASHMINA_ID")
    @ManyToOne
    private Pashmina pashmina;

Описание

public class Description implements Serializable {

    private static final long serialVersionUID = 1L;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Id

    @Column(name = "DESCRIPTION_ID")
    private int descriptionId;

    @Column(name = "PASHMINA_DESCRIPTION")
    private String pashminaDescription;

    @JoinColumn(name = "PASHMINA_ID", referencedColumnName = "PASHMINA_ID")
    @ManyToOne
    private Pashmina pashmina;

Для каждого из классов Id вставляется с использованием триггера в базе данных Oracle. Спасибо!

Дайте мне знать, если вы, ребята, не понимаете меня

Вот так я отправляю объект в контроллер enter image description here

Ответы [ 2 ]

0 голосов
/ 30 июня 2018

Я думаю, что проблема заключается в несовпадении имени класса сущности, которое вы отправляете из ajax-запроса. Я вижу, что вы отправляете PashminaModel сущность, но вы используете только Pashmina в своем весеннем классе POJO. Попробуйте изменить свой класс сущности т.е. Pashmina до PashminaModel, Description до DescriptionModel, Image до ImageModel, Pashmina до PashminaModel.

Надеюсь, это сработает.

0 голосов
/ 28 июня 2018

Предполагая, что ваша пашмина правильно устанавливает отношения, вам нужно только:

    if (pashmina != null) {
        try {
            pashminaService.insert(pashmina);

            return new ResponseEntity<>(HttpStatus.OK);

        } catch (HibernateException e) {
            return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
        }
    } else {
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

В любом случае я бы никогда не использовал сущность Hibernate для отправки или получения от клиента - вы никогда не можете доверять своему клиенту, чтобы он не изменял ваши данные таким образом, чтобы это было вредно.

Чтобы правильно установить отношения, вам нужно установить отношения с обеих сторон, если обе стороны имеют сопоставление с другой стороной, например:

public void addPashminaColour(PashminaColour color) {
    this.pashminaColour.add(color);
    color.setPashmina(this);
}

Альтернатива, с четким разделением модели и объекта:

    public @Async ResponseEntity<String> insertPashmina(@RequestBody PashminaModel pashminaModel) {
    if (pashmina != null) {
        try {

            PashminaModel pashmina = pashminaConverter.convert(pashminaModel);

            pashminaService.insert(pashmina);

            return new ResponseEntity<>(HttpStatus.OK);
            ...
        }
        ...
    }


public class PashminaConverter {

    public Pashmina convert(PashminaModel model) {
        Pashmina pashmina = new Pashmina();

        // copy primitive fields from model to entity

        for (ColorModel colorModel : model.getColors()) {
            pashmina.addColor(colorConverter.convert(colorModel);
        }

        // same for DescriptionModel
    }
}

public class ColorConverter {

    public PashminaColour convert(ColorModel model) {
        // copy primitive fields from model to entity
    }

}

public class Pashmina {

    ...

    public void addColor(PashminaColour color) {
        this.pashminaColour.add(color);
        color.setPashmina(this);
    }

    ...
}
...