Не удается сохранить сущность с общим идентификатором - PullRequest
0 голосов
/ 26 августа 2018

Я практикую технологии JavaEE.Сейчас я сосредоточен на JPA с Hibernate.В проекте есть следующие объекты:

Книга:

@Entity @Table(name = "book")
public class Book extends BaseEntity<Long> {
   @Id
   private Long id;

   @NotNull
   private String name;

   @OneToOne(mappedBy = "book", cascade = CascadeType.ALL)
   private BookDetails details;

   //getters/setters
}

BookDetails:

@Entity
@Table(name = "book_details")
public class BookDetails extends BaseEntity<Long> {

    @Id
    private Long id;

    @MapsId
    @OneToOne
    private Book book;

    @NotNull
    @Column(name = "number_of_pages")
    private int numberOfPages;

    //getters/setters
}

Теперьсоответствующие классы обслуживания EJB:

BookService:

@Stateless
public class BookService extends BaseEntityService<Long, Book> {

    public void createBook(Book book) {
        super.getEntityManager().persist(book);
    }

    //update, delete, find and findAll methods
}

BookDetailsService:

@Stateless
public class BookDetailsService extends BaseEntityService<Long, BookDetails> {

    public void createBookDetails(BookDetails details) {
        super.getEntityManager().persist(details);
        //super.persist(details); //This method would not work to persisting entity with shared Id, because it verifies if ID is null
    }
    //update, delete and find methods
}

Проблема:

Когда я пытаюсь сохранить новую книгу вместе с ее подробностями следующим образом:

Book b = new Book();
b.setId(123L);
b.setName("Bible");

bookService.createBook(b);
//The entity Book  is correctly persisted in the DB.
BookDetails d = new BookDetails();
d.setNumberOfPages(999);
d.setBook(b);

//b.setDetails(d); //don't do this

bookDetailsService.createBookDetails(d);
//BookDetails is not persisted in the DB, throws exception....

Выдает следующее исключение:

java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '123' for key 'PRIMARY'

Сущность Book сохраняется, но не BookDetails.


Я следовал этим урокам:

Дополнительная информация:

  • JDK 1.8
  • Payara 5
  • MySQL 8.0
  • Hibernate 5.3.4
  • OmniPersistence библиотека.( Утилиты для JPA, JDBC и источников данных )

Вы можете посмотреть репозиторий проекта здесь .

Ответы [ 3 ]

0 голосов
/ 26 августа 2018

@ OneToOne в свойстве BookDetails класса Book указывает, что существует взаимно-однозначное сопоставление между Book и BookDetails.Также обратите внимание на использование cascade = CascadeType.ALL . Поскольку сущность BookDetails не может существовать без сущности Book, с этим параметром каскада сущность BookDetails будет обновляться / удаляться при последующем обновлении / удалении сущности Book.

0 голосов
/ 29 августа 2018

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

При вызове бизнес-метода EJB, в котором классы сохраняются, по завершении этого метода транзакция завершается, поэтому контекст постоянства закрывается и присоединенные классы (управляемые) становятся отсоединенными (неуправляемыми). Смотрите это .

Итак, после сохранения Book b:

bookService.createBook (b);

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

d.setBook (b);

Это то, что нужно сделать, чтобы сохранить сущность, которая разделяет Id, необходимо управлять родительской сущностью (в данном случае b).


Есть два решения, которые я мог бы найти:

Решение 1:

Прикрепить книгу b к контексту постоянства транзакции создания деталей. См это .

b = getEntityManager.merge(b);

Решение 2: (Тот, который я выбрал)

Выполните вызов бизнес-метода BookService в бизнес-методе BookDetailsService, что предполагает перенос внедрения зависимости. Таким образом, одна транзакция выполняется путем сохранения двух сущностей.

//BookDetailsService class
@Inject
BookService bookService;

public void createBookDetails(BookDetails details) {
    Book b = new Book();
    b.setId(details.getId());
    b.setName("Bible");

    bookService.createBook(b);

    details.setBook(b);//b still managed

    super.persist(details);
}

Я думаю, что это решение более понятное и согласованное, потому что BookDetailsService всегда будут нуждаться в услугах, начиная с BookService.

0 голосов
/ 26 августа 2018

Вы должны добавить каскадный тип в детали книги:

@OneToOne(mappedBy = "book", cascade = CascadeType.ALL)
private BookDetails details;

См. здесь для более подробной информации. CascadeType.ALL будет выполнять все операции, такие как сохранение, удаление и объединение при сохранении сущности книги. Теперь, когда мы добавили CascadeType.ALL в сущность Book, вы должны установить объект bookdetails в book. Смотрите ниже:

Book b = new Book();
BookDetails d = new BookDetails();
b.setBookDetails(d);
b.setId(123L);
b.setName("Bible");

d.setId(111L); //random id that is not existing if d is new record
d.setNumberOfPages(999);
bookService.createBook(b);

Сохранение сущности книги сохранит как книгу, так и сущность сведений о книге. Вы также можете попробовать hibernate.show_sql=true, чтобы увидеть, какие все запросы выполняются при сохранении сущности книги.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...