JPA ManyToMany дубликат выпуска ключа - PullRequest
0 голосов
/ 31 мая 2018

У меня следующая проблема.У меня есть 2 сущности, Кино и Актер.

Отношение

В фильме есть несколько актеров, но актер может быть в нескольких фильмах.Теперь проблема возникает, когда я пытаюсь добавить 2 фильма, у которых есть общий актер.

Допустим, я добавляю Deadpool, а после этого я добавляю Deadpool 2. Когда я добавляю второйфильм Я получаю следующую ошибку:

Оператор был прерван, поскольку он вызвал бы дублирование значения ключа в ограничении уникального или первичного ключа

Теперь это допустимо, потому чтоjpa вставляет актера в базу данных, которая уже существует.Я не знаю, как я могу решить эту проблему, я получаю идентификаторы из TheMovieDatabase и не хочу, чтобы в моей базе данных были дубликаты Актеров.

MOVIE:

@Entity(name = "Movie")
public class Movie {

//instance variables
@Positive
@Id
private long tmdbId;

...

@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name = "movie_actor",
        joinColumns = @JoinColumn(name = "movie_tmdbid"),
        inverseJoinColumns = @JoinColumn(name = "actor_id")
)
private Set<Actor> actors = new HashSet<>();

...

Актер:

@Entity(name = "Actor")
public class Actor {

@Id
private long id;

...

@ManyToMany(mappedBy = "actors")
private Set<Movie> movies = new HashSet<>();

Метод добавления Jpa

    public void addMovie(Movie movie) {
    try {
        //open connection
        openConnection();

        //check
        if (movie == null) {
            throw new DatabaseException("You cannot add an empty movie");
        }

        //contains only looks in the current persistence context
        if (entityManager.find(Movie.class,movie.getTmdbId()) != null) {
            throw new MovieAlreadyExistsException("This movie already exists!");
        }

        //begin transaction
        entityManager.getTransaction().begin();

        //add movie & commit
        entityManager.persist(movie);
        entityManager.getTransaction().commit();

    }catch (MovieAlreadyExistsException error){
        throw new MovieAlreadyExistsException(error.getMessage(),error);
    } catch (Exception error) {
        throw new DatabaseException(error.getMessage(), error);
    } finally {
        closeConnection();
    }
}

Метод, который устанавливает актеров: Это займет актеров из TheMovieDatabase, а addMovie - это актера из jpa за фасадом.

//add a movie
@PostMapping(value = "/add")
public String saveMovie(@ModelAttribute("movie") @Valid Movie movie, BindingResult result) {
    ...

    try{
            //set actors
        Set<Actor> actors = new HashSet<>(mediaService.getMovieActors(movie.getTmdbId()));
        movie.setActors(actors);

        //add movie with actors
        movieService.addMovie(movie);

StackTrace:

Внутреннее исключение: org.apache.derby.shared.common.error.DerbySQLIntegrityConstraintViolationException: оператор был прерван, так как он вызвал бы дублирование значения ключа в ограничении уникального или первичного ключа или уникальном индексе, определенном как «SQL180530224955890», определенном в «ACTOR».Код ошибки: 20000 Вызов: INSERT INTO ACTOR (ID, MOVIECHARACTER, NAME, PROFILEPICTURE) VALUES (?,?,?,?) Bind => [4 параметра привязаны] Запрос: InsertObjectQuery (model.movie.actor.Actor@d681)] с основной причиной ОШИБКА 23505: Оператор был прерван, так как он вызвал бы дублирование значения ключа в ограничении уникального или первичного ключа или уникальном индексе, идентифицированном как «SQL180530224955890», определенном в «ACTOR».в org.apache.derby.client.am.ClientStatement.completeExecute (неизвестный источник) в org.apache.derby.client.net.NetStatementReply.parseEXCSQLSTTreply (неизвестный источник) в org.apache.derby.client.net.NetStatementRepte.read(Неизвестный источник) в org.apache.derby.client.net.StatementReply.readExecute (Неизвестный источник) в org.apache.derby.client.net.NetPreparedStatement.readExecute_ (Неизвестный источник) в org.apache.derby.client.am.ClientPreparedStatement.readExecute (Неизвестный источник) в org.apache.derby.client.am.ClientPreparedStatement.flowExecute (Неизвестный источник) в org.apache.derby.client.am.ClientPreparedStatement.executeUpdateX или неизвестный источник (неизвестный источник).client.am.ClientPreparedStatement.executeUpdate (Неизвестный источник) по адресу org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect (DatabaseAccessor.java:895) по адресу org.eclipse.persistence.internal.databaseorcessecuJava: 967) в org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall (DatabaseAccessor.java:637) в org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall (DatabaseAccessor.java:564) в org.eclipse.persistence.internal.sessions.AbstractSession.allicExSession.Java: 2093) в org.eclipse.persistence.sessions.server.ClientSession.executeCall (ClientSession.java:309) в org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall (DatasourceCallQueryMeecism.j).persistence.internal.queries.DatasourceCallQueryMechanism.executeCall (DatasourceCallQueryMechanism.java:256) при org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.insertObject (DatasourceCallQueryMechanism.java:405) при org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject (StatementQueryMechanism.java:165) в org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject (StatementQueryMechanism.java:180)в org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite (DatabaseQueryMechanism.java:502) в org.eclipse.persistence.queries.InsertObjectQuery.executeCommit (InsertObjectQuery.javasertOip.yery.lip.uery.uipse.user.user.user.user.user.user.user или.executeCommitWithChangeSet (InsertObjectQuery.java:90) при org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet (DatabaseQueryMechanism.java:314) при org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery (WriteObjectQuery.java:58) вorg.eclipse.persistence.queries.DatabaseQuery.execute (DatabaseQuery.java:911) по адресу org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork (DatabaseQuery.java:810) по адресу org.eclipse.persistence.quvel.OodeQuifyUquifyObjectLevelModifyQuery.java:108) в org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork (ObjectLevelModifyQuery.java:85) в org.eclipse.persistence.internal.Sessions.UnitOfWorkImpl.internalExecuteQuery (UnitOfWorkImpl.java:2979) в org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery (AbstractSession.java:1892) в org.eclipse.persistence.internal.SessionJava: 1874) в org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery (AbstractSession.java:1824) в org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet (CommitManecip или or CommitManager.java).persistence.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet (CommitManager.java:194) в org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet (CommitManager.jsessgAl.in.writeAllObjectsWithChangeSet (AbstractSession.java:4384) в org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase (UnitOfWorkImpl.java:1491) в org.eclipse.persistence.internal.sessions.UnitWorkImpl.commitToDatabaseWithChangeSet (UnitOfWorkImpl.java:1581) в org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork (RepeatableWriteUnitOfWork.java:278) в org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume (UnitOfWorkImpl.java:1218) в org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit (EntityTransactionImpl.java:134) в model.db.types.MovieDatabaseJpa.addMovie (MovieDatabaseJpa.java:66) в модели. MovieService.java: 19) at web.controller.MovieController.saveMovie (MovieController.java:72) в sun.reflect.NativeMethodAccessorImpl.invoke0 (родной метод) в sun.reflect.NativeMethodAccessorImpl.invoke (собственный).отражения.в орг.сpringframework.web.method.support.InvocableHandlerMethod.invokeForRequest (InvocableHandlerMethod.java:136) в org.springframework.web.servlet.mvc.method.annotation.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod (RequestMappingHandlerAdapter.java:870) в org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdaping.servlet.mvc.method.AbstractHandlerMethodAdapter.handle (AbstractHandlerMethodAdapter.java:87) в org.springframework.web.servlet.DispatcherServlet.doDispatch (DispatcherServlet.java:991)по адресу org.springframework.web.servlet.DispatcherServlet.doService (DispatcherServlet.java:925) по адресу org.springframework.web.servlet.FrameworkServlet.processRequest (FrameworkServlet.java:978) at org.sprervwork(FrameworkServlet.java:881)

Может кто-нибудь указать мне правильное направление?Спасибо!

1 Ответ

0 голосов
/ 31 мая 2018

Я решил проблему:

Я использовал слияние вместо постоянного, потому что, если сущность существует, она обновит ее, в противном случае вставит.

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