a different object with the same identifier value was already associated with the session when trying to persist entity

北战南征 提交于 2020-01-13 10:22:06

问题


I have a slight problem that I don't know how to solve. Could you help me please? When I am trying to persist entity I get next exception:

12:47:39,398 ERROR [org.black.dmitriy.entityHome.ScheduleHome] (http--127.0.0.1-8080-1)  javax.persistence.EntityExistsException: a different object with the same identifier value was already associated with the session: [org.black.dmitriy.entity.Schedule#1]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1333) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1289) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1295) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:859) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_04]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_04]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_04]
at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_04]
at org.jboss.seam.persistence.EntityManagerInvocationHandler.invoke(EntityManagerInvocationHandler.java:46) [jboss-seam.jar:2.3.0.Final]
at $Proxy81.persist(Unknown Source) at org.jboss.seam.framework.EntityHome.persist(EntityHome.java:84) [jboss-seam.jar:2.3.0.Final]
at org.black.dmitriy.entityHome.ConversationHome.tryPersist(ConversationHome.java:147) [ejb.jar:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_04]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_04]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_04]
at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_04]
at org.jboss.seam.util.Reflections.invoke(Reflections.java:22) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:32) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:28) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.core.ConversationInterceptor.aroundInvoke(ConversationInterceptor.java:65) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.transaction.TransactionInterceptor$1.work(TransactionInterceptor.java:97) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.util.Work.workInTransaction(Work.java:61) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.transaction.TransactionInterceptor.aroundInvoke(TransactionInterceptor.java:91) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:44) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:186) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:104) [jboss-seam.jar:2.3.0.Final]
at org.black.dmitriy.entityHome.ScheduleHome_$$_javassist_seam_8.tryPersist(ScheduleHome_$$_javassist_seam_8.java) [ejb.jar:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_04]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_04]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_04]
at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_04]
at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:335) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:348) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.parser.AstPropertySuffix.invoke(AstPropertySuffix.java:58) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.parser.AstValue.invoke(AstValue.java:96) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.component.UICommand.broadcast(UICommand.java:315) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158) [jboss-seam.jar:2.3.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:397) [jbossweb-7.0.13.Final.jar:]
at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_04]

I use seam 2.3, hibernate. I have one insert statement in my import.sql file:

INSERT INTO Schedules (id, name, dayCount, lessonCount, firstTermSize, secondTermSize, subgroupSize) VALUES(1, '2012/2013', 5, 8, 9, 9, 18)

which inserts one enity into table Schedules.

Then I create new Schedule entity throw web page using EntityHome

@Name("scheduleHome")
@Scope(ScopeType.CONVERSATION)
public class ScheduleHome extends ConversationHome<Schedule> {
    private static final long serialVersionUID = 1L;

    public ScheduleHome() {
    }

    @Override
    protected boolean isUnique() {
        Schedule schedule = getInstance();
        Schedule foundSchedule = ScheduleDAO.instance().getByName(schedule.getName());

        if ((foundSchedule != null) && (!foundSchedule.equals(schedule))) {
            showExistsErrorMessage(getInstance().getName());
            return false;
        }

        return true;
    }

    @Override
    protected Schedule createInstance() {
        return new Schedule();
    }

    @Override
    public String getEditOutcome() {
        return "scheduleEdit";
    }

    @Override
    protected void prepareEntityForSaving() {

    }
}

and the superclass

public abstract class ConversationHome<T> extends EntityHome<T> {
    private static final long serialVersionUID = 1L;
    private String parentView;

    public boolean isParentViewExists() {
        return parentView != null && parentView.length() > 0;
    }

    public void setParentView(String parentView) {
        this.parentView = parentView;
    }

    public String getParentView() {
        return parentView;
    }

    public abstract String getEditOutcome();

    protected abstract void prepareEntityForSaving();

    protected abstract boolean isUnique();

    @Override
    @Create
    public void create() {
        create(false);
    }

    protected void create(boolean createNestedConversation) {
        Conversation conversation = Conversation.instance();
        if (!createNestedConversation && conversation.isLongRunning()) {
            getLog().debug("conversation already started, nested will not create(isLongRunning = #0, isNested = #1)", conversation.isLongRunning(), conversation.isNested());
        } else {
            conversation.begin(false, conversation.isLongRunning());
            conversation.changeFlushMode(FlushModeType.MANUAL);
            getLog().debug("create(isLongRunning = #0, isNested = #1, id = #2)", conversation.isLongRunning(), conversation.isNested(), conversation.getId());
        }
        super.create();
    }

    private boolean init(Long id) {
        FacesContext context = FacesContext.getCurrentInstance();
        setParentView(Pages.getViewId(context));

        if (id != null) {
            setId(id);
            try {
                getInstance();
                getLog().debug("instance initialized #0", getInstance());
            } catch (EntityNotFoundException e) {
                getLog().error(e);
                return false;
            }
        }
        return true;
    }

    public String startEdit(Long id) {
        getLog().debug("start editing #0", id);
        if (init(id)) {
            return getEditOutcome();
        } else {
            return cancel();
        }
    }

    public String cancel() {
        if (isManaged()) {
            getEntityManager().refresh(getInstance());
        }
        return returnToParent();
    }

    @End
    protected String returnToParent() {
         if (isParentViewExists()) {
                Conversation conversation = Conversation.instance();
                getLog().debug("end conversation(id = #0, isLongRunning = #1, isNested = #2)",
                        conversation.getId(), conversation.isLongRunning(), conversation.isNested());
                conversation.end(true);
                return getParentView();
            } else {
                clearInstance();
                return null;
            }
    }

    public String tryPersist() {
        if (isUnique()) {
            try {
                prepareEntityForSaving();

                String outcome = persist();
                if (!"failed".equals(outcome)) {
                    return returnToParent();
                }
            } catch (Exception e) {
                getLog().error(getInstance(), e);
                showSaveErrorMessage(e);
            }
        }
        return "failed";
    }
}

and when i try to persist it i get this exception. and message on web page

Save error with message: a different object with the same identifier value was already associated with the session: [org.black.dmitriy.entity.Schedule#1]

It seams that hibernate set id property to 1, but I already have entity with id = 1, because I manually created it throw import.sql.

Here is my Schedule entity :

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;

@Entity
@Table(name = "Schedules")
public class Schedule {

    @Id
    @GeneratedValue
    @Column(name = "id", nullable = false)
    private Long id;

    @NotNull
    @Column(name = "name", nullable = false, length = 40)
    private String name;

    @Column(name = "dayCount")
    private int dayCount = 5;

    @Column(name = "lessonCount")
    private int lessonCount = 8;

    @Column(name = "firstTermSize")
    private int firstTermSize = 9;

    @Column(name = "secondTermSize")
    private int secondTermSize = 9;

    @Column(name = "subgroupSize")
    private int subgroupSize = 18;

    @OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, targetEntity = Faculty.class)
    private List<Faculty> faculties = new ArrayList<>();

    @OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, targetEntity = Building.class)
    private List<Building> buildings = new ArrayList<>();

    public Schedule() {

    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getDayCount() {
        return dayCount;
    }

    public void setDayCount(int dayCount) {
        this.dayCount = dayCount;
    }

    public int getLessonCount() {
        return lessonCount;
    }

    public void setLessonCount(int lessonCount) {
        this.lessonCount = lessonCount;
    }

    public int getFirstTermSize() {
        return firstTermSize;
    }

    public void setFirstTermSize(int firstTermSize) {
        this.firstTermSize = firstTermSize;
    }

    public int getSecondTermSize() {
        return secondTermSize;
    }

    public void setSecondTermSize(int secondTermSize) {
        this.secondTermSize = secondTermSize;
    }

    public int getSubgroupSize() {
        return subgroupSize;
    }

    public void setSubgroupSize(int subgroupSize) {
        this.subgroupSize = subgroupSize;
    }

    public List<Faculty> getFaculties() {
        return faculties;
    }

    public void setFaculties(List<Faculty> faculties) {
        this.faculties = faculties;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Schedule)) {
            return false;
        }
        Schedule other = (Schedule) obj;
        if (id == null) {
            if (other.id != null) {
                return false;
            }
        } else if (!id.equals(other.id)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return this.name;
    }
}

As you can see there is @GeneratedValue annotation on id property, so I think that hibernate should generate id himself and hibernate should know that there is entity in database with id = 1, and set id in new entity = 2. But Hibernate sets id in new entity to 1. Could you halp me please?


回答1:


The problem was how hibernate generates your id's, it starts from 1. When it assigns 1 to an object before saving it into database, it sees a row with same id already exists in the database and causes the exception. The simple and natural solution of this problem is simply to restrict hibernate, so that it can not assign 1 as an id to any object of the concerning class (in your case).

Solution for mySql:

If you are using mySql, you can create table manually and set the auto increment like:

  CREATE TABLE IF NOT EXISTS `testTable` (
      `id` number(11) NOT NULL AUTO_INCREMENT,
       ...,
       ...,
       ...,
       PRIMARY KEY (`id`)
 ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2; //assigning id by hibernate, will start from 2.

And in your domain class you can have id annotated like bellow:

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
public long getId() {
   ....
}

GenerationType.AUTO by default uses auto increment in mySql. and after setting AUTO_INCREMENT=2 hibernate will start assigning id's from 2 (hence 1 is skipped).

Solution for Oracle:

The same thing for oracle can be done if you restrict hibernate use a "sequence" and you set the initial point of the sequence as your wish. You can create a sequence to be start from 2 and increment by 1 like bellow:

 create sequence idSequence
        start with 2
        increment by 1
        maxvalue 9999999999999;

And you can specify your sequence to be used to generate id's of your domain class's object like bellow:

@Id
@SequenceGenerator(name = "idGeneratorSeq", sequenceName = "idSequence")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "idGeneratorSeq")
@Column(name = "ID")
public long getId() {
   ....
}

And your problem is sovled.




回答2:


Do the following steps before calling persist() method.

First detach your current instance

getEntityManager().detach(getInstance());

Now set its Id to null

getInstance().setId(null);

Now persist

String outcome = persist();


来源:https://stackoverflow.com/questions/13762713/a-different-object-with-the-same-identifier-value-was-already-associated-with-th

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!