首页 > 解决方案 > 无法在 Spring-boot 中找出具有相同标识符值的对象

问题描述

“trace”:“org.springframework.dao.DataIntegrityViolationException:具有相同标识符值的不同对象已与会话关联:[com.ffcalendar.calendarDemo.models.User#1];嵌套异常是 javax.persistence.EntityExistsException :具有相同标识符值的不同对象已与会话关联:[com.ffcalendar.calendarDemo.models.User#1]\r\n\tat org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java :400)\r\n\tat org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:235)\r\n\tat org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java :551)\r\n\tat org.springframework.dao.support。ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)\r\n\tat org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)\r\n\tat org.springframework.dao.support.PersistenceExceptionTranslationInterceptor。调用(PersistenceExceptionTranslationInterceptor.java:152)\r\n\tat

标签: javaspringspring-bootrest

解决方案


“具有相同标识符值的不同对象已与会话关联”

在持久性上下文中只允许 1 个具有特定 id 的托管实例。这意味着对于特定类,您只能拥有 1 个实例,例如id =322,该实例被认为处于 JPA 的托管状态。如果您有来自同一类的另一个具有相同 Id 的分离实例,并且您尝试重新附加它,那么您会收到您遇到的错误。

如果您提供有关如何保存这些实体的更多信息,我们将能够找到错误所在。

根本原因就是我所描述的。

编辑:在问题中提供更多信息后

我有很多怀疑,因为你的代码看起来不是很干净,但无论如何我都会从显而易见的开始

public class CalendarEvent {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

     @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((eventDateTime == null) ? 0 : eventDateTime.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            CalendarEvent other = (CalendarEvent) obj;
            if (eventDateTime == null) {
                if (other.eventDateTime != null)
                    return false;
            } else if (!eventDateTime.equals(other.eventDateTime))
                return false;
            return true;
        }
     }

在此处查看您的代码的这一部分。对于 JPA,您已声明实体将用Long id.

但是,稍后您提供了一个 equals 和一个仅考虑eventDateTime.

所以一个包含 CalendarEvents 的列表可以有多个具有相同 id 和不同 eventDateTime 的 CalendarEvents。这对 JPA 来说绝对是错误的。

首先实现仅考虑 Long id 字段的 equals 和 hashcode。如果这不是特定的根本原因,我们会走得更远,但考虑到您使用 CalendarEvents 的方式,这肯定会改变

old_events = user.getEvents(); //DB fetch
old_events.addAll(new_events);
Set<CalendarEvent> set_event = new HashSet<CalendarEvent>(old_events);

在这里,您会受到错误的哈希码和等于的影响。您尝试过滤一组独特的事件。但是该集合将仅保留具有唯一 eventDateTime 的事件。考虑到在您的代码中,您在集合中添加了 2 次相同的元素,它们中的大多数将具有相同的 id。

在坚持的后期,JPA 不会期望这种情况发生。


推荐阅读