【问题标题】:detached entity passed to persist: model.Company传递给持久化的分离实体:model.Company
【发布时间】:2018-09-22 04:52:19
【问题描述】:

我将分离的实体传递给持久化:模型。我使用@OneToMany 映射时的公司。我尝试了不同的方法,但结果相同。 我添加了 @OneToMany 和 CascadeTypes Persist 等等。删除那些。 设置经理并尝试坚持,评论设置经理并尝试坚持。他们都没有工作。

公司:

@Entity
public class Company {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private int id;

    private int age;

    @ElementCollection
    private Set<Manager> managers;

    private String name;


    public int getId() {
        return this.id;
    }

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

    public String getName() {
        return this.name;
    }

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

    public void setManagers(Set<Manager> managers) {
        this.managers = managers;
    }


    public Set<Manager> getManager() {
        return managers;
    }

}

经理

@Entity
public class Manager {

    @Id
    @GeneratedValue
    private int id;

    private String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

测试

public class Test {
    public static void main(String args[]) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatestproject");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();

    //  Manager m1 = new Manager();
    //  m1.setName("abc");
    //  Manager m2 = new Manager();
    //  m2.setName("def");
    //  Set<Manager> managers = new HashSet();
    //  managers.add(m1);
    //  managers.add(m2);
    //  

        Company company = new Company();
        company.setId(1);
        company.setName("LTE");
    //  company.setManagers(managers);


        tx.begin();

        em.persist(company);
        tx.commit();
        System.out.println("Done");
    }
}

【问题讨论】:

    标签: java jpa orm jpa-2.0


    【解决方案1】:

    首先,可以将带有@MappedSuperClass 注释的抽象基类用于通用方面,例如主键管理:

    @MappedSuperClass
    public abstract class AbstractEntity {
    
        @Id
        @Column(name = "id")
        //@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pk-sequence")
        //@SequenceGenerator(name = "pk-sequence", sequenceName = "ID_GEN", allocationSize = 1)
        protected Long objectID = -1;
    
        @Version
        private int version;
    
        public int getVersion() {
            return version;
        }
    
        public long getObjectID() {
            return objectID;
        }   
    }
    

    注意:objectIDversion 属性都没有设置器。因此,在运行时,这两个值都将保持由 ORM 控制。这样,EntityManager 的实例可以安全地管理lifecycle of an Entity。有关@Version 的详细信息,请参阅另一个答案。此外,可以增强这种通用方法以包括其他通用方面,例如创建/修改日期/时间戳。

    这将大大简化您现有的@Entity 类。

    @Entity
    public class Company extends AbstractEntity  {
        private static final long serialVersionUID = 1L;
    
        private int age;
    
        // @ElementCollection <-- Use a 1-n annotation here instead.
        @OneToMany(cascade=CascadeType.ALL) 
        // to ensure non persisted manager objects will be persisted via a cascade chain here...
        private Set<Manager> managers;
    
        private String name;
    
        public String getName() {
            return this.name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setManagers(Set<Manager> managers) {
            this.managers = managers;
        }
    
    
        public Set<Manager> getManager() {
            return managers;
        }
    
    }
    

    还请注意,我注释掉了@ElementCollection,而是更改了映射以使用@OneToMany 注释。这背后的基本原理是 ElementCollection 只能用于指定 a one-to-many relationship to an Embeddable object, or basic types(例如,通过 Set 等引用),而实体类 Manager 并非如此。

    最后,

    @Entity
    public class Manager extends AbstractEntity {
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    通过上述更改,您应该能够运行Test#main(..) 方法中提供的代码。请注意,在坚持之前,您仍应检查正确的关联顺序。我没有测试您问题中提供的代码 sn-p ;不过你应该可以让它工作。

    希望对你有帮助。

    【讨论】:

      【解决方案2】:

      您正在使用 company.setId(1); 手动设置公司 ID。

      @GeneratedValue 最好不要管。

      持久化上下文将假定记录已经存在,但分离,因为设置了 id 但实体不在当前持久化上下文中(由当前的 EntityManager 表示)。

      【讨论】:

        猜你喜欢
        • 2013-06-26
        • 1970-01-01
        • 2017-04-01
        • 1970-01-01
        • 2017-10-21
        • 1970-01-01
        • 2018-05-25
        • 2018-09-09
        • 2015-12-26
        相关资源
        最近更新 更多