当前位置: 首页 > 知识库问答 >
问题:

无法在Spring Boot中找出相同标识符值的对象

孟英叡
2023-03-14

“跟踪”:“org.springframework.dao.DataIntegrityViolationException:具有相同标识符值的不同对象已与会话关联:[com.ffcalendar.calendarDemo.models.User#1]; 嵌套的异常是javax。坚持不懈EntityExistsException:具有相同标识符值的另一个对象已与会话[com.ffcalendar.calendarDemo.models.User#1]\r\n\t关联。springframework。奥姆。jpa。EntityManagerFactoryUtils。ConvertJPAAccessException如果可能(EntityManagerFactoryUtils.java:400)\r\n\t组织。springframework。奥姆。jpa。小贩HibernatePadialect。TranslateException如果可能(HibernateJpaDialect.java:235)\r\n\t org。springframework。奥姆。jpa。AbstractEntityManagerFactoryBean。TranslateException如果可能(AbstractEntityManagerFactoryBean.java:551)\r\n\t org。springframework。刀。支持ChainedPersistenceExceptionTranslator。TranslateException如果可能(ChainedPersistenceExceptionTranslator.java:61)\r\n\t组织。springframework。刀。支持数据附件。translateIfNecessary(DataAccessUtils.java:242)\r\n\t组织。springframework。刀。支持PersistenceExceptionTranslationInterceptor。调用(PersistenceExceptionTranslationInterceptor.java:152)\r\n\t

共有2个答案

饶承宣
2023-03-14

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

持久性上下文中只允许1个具有特定id的托管实例。这意味着对于一个特定的类,您只能有一个实例,例如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,您已声明实体将通过长id进行区分。

然而,稍后您将提供一个equals和一个hashcode方法,该方法仅考虑eventDateTime

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

通过执行只考虑长ID字段的均衡器和哈希代码开始。如果这不是具体的根本原因,我们将更进一步,但考虑到您使用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预计不会出现这种情况。

钮长恨
2023-03-14

用户可以参加许多活动。一个事件可以有很多用户。因此,它将是@ManyTo多项映射。只使用两个表Calendreent和User

用户:

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String name;
    @ManyToMany
    @JoinTable( name ="user_events", joinColume = @JoinColume(name = "user_id"), inverseJoinColume = @JoinColume(name = "event_id"))
    private List<Event> events = new ArrayList<>();

活动:

@Entity
public class Event {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;    
    private String title;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime eventDateTime;
    @ManyToMany(mappedBy = "events")
    private List<User> users = new ArrayList<>();

在用户实体中添加每个事件后保存用户。

 类似资料: