Java JPA Unit Test保存2项

时间:2015-07-22 13:51:20

标签: java hibernate jpa jboss-arquillian

我有一个简单的 {{#each filteredOffers as |offer|}} ... {{/each}} 设置,包含2个实体 - @OneToManyItem,并且我遇到了一个有趣的问题。当我的集成测试创建Group时,向其添加Group并保存ItemGroup的2个实例最终会被保存。有什么想法吗?我正在使用Hibernate,如果重要的话:

  

项目实体

Item
  

群组实体

@Entity
public class NamedEntity implements java.io.Serializable {
    Long             id;

    @NotNull
    String           name;

    NamedEntityGroup namedEntityGroup;

    NamedEntityType  type;

    @Enumerated(EnumType.STRING)
    public NamedEntityType getType() { return type; }

    @Id
    @GeneratedValue
    public Long getId() { return id; }

    public String getName() { return name; }

    @JoinColumn(name = "NamedEntityGroupId")
    @JsonBackReference
    @ManyToOne(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
    public NamedEntityGroup getNamedEntityGroup() { return  this.namedEntityGroup; }
}
  

DAO

    @Entity
    public class NamedEntityGroup implements Serializable {
        Long              id;

        String            name;

        List<NamedEntity> namedEntities;

        @Id
        @GeneratedValue
        public Long getId() { return this.id; }

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

        @JsonManagedReference
        @OneToMany(cascade = { CascadeType.ALL }, mappedBy = "namedEntityGroup", fetch = FetchType.EAGER)
        public List<NamedEntity> getNamedEntities() { return this.namedEntities; }

        public void addNamedEntity(NamedEntity ne) {
            if (this.namedEntities == null) {
                this.namedEntities = new ArrayList<NamedEntity>();
            }
            if (!namedEntities.contains(ne)) {
                this.namedEntities.add(ne);
            }
            ne.setNEG(this);
        }
    }
  

测试方法

    public void save(NamedEntity ne) throws EntityValidationException {
        validate(ne);
        if(ne.getNamedEntityGroup() != null) {
            if(!em.contains(ne.getNamedEntityGroup())) {
                ne.setNamedEntityGroup(em.merge(ne.getNamedEntityGroup()));
                em.persist(ne);
                return;
            }
        } 

        em.persist(ne); 
    }

这是输出:

    @Test
    public void testAddNamedEntityToExistingGroup() throws EntityValidationException {
        int neSize = ed.getAllNamedEntities().size();
        NamedEntityGroup neg = ed.getAllNamedEntityGroups().iterator().next();

        assertNotNull(neg);
        assertTrue(neg.getNamedEntities().size() == 0);
        em.detach(neg);

        NamedEntity n = new NamedEntity();
        n.setName("Hello");

        neg.addNamedEntity(n);
        n.setNamedEntityGroup(neg);

        n.setType(NamedEntityType.DEFAULT);

        ed.save(n);
        for(NamedEntity e : ed.getAllNamedEntities()) {
            L.error("Entity: {}", e);
        }

        assertTrue("Size is " + ed.getAllNamedEntities().size() + " but it should be " + (neSize + 1) + " the group has "
                + neg.getNamedEntities().size() + " entities (should be 1) " + ed.getAllNamedEntities(), neSize + 1 == ed.getAllNamedEntities().size());
    }

我的Entity: NamedEntity [id=1, name=Super Mario Brothers, namedEntityGroup=null, type=null] Entity: NamedEntity [id=3, name=Mario Kart, namedEntityGroup=null, type=null] Entity: NamedEntity [id=5, name=F-Zero, namedEntityGroup=null, type=null] Entity: NamedEntity [id=7, name=Hello, namedEntityGroup=NamedEntityGroup [id=2, name=Super Mario Brothers, COUNT(entity)=1], type=DEFAULT] Entity: NamedEntity [id=8, name=Hello, namedEntityGroup=NamedEntityGroup [id=2, name=Super Mario Brothers, COUNT(entity)=1], type=DEFAULT] 7在输出中是重复的,因为8方法正在插入一个项目2次。

1 个答案:

答案 0 :(得分:1)

您的DAO save方法很难看,重构它,否则会出现更多像这样的问题。 :)

问题出在DAO em.merge(ne.getNamedEntityGroup())方法的save中。由于NamedEntityGroup级联ALLnamedEntitiesMERGE级联到ne,这是暂时的(未保存),导致要创建的NamedEntity实例。 ne实例已从namedEntities集合中删除,并将其副本放入其中。 Session.merge javadoc

  

使用。将给定对象的状态复制到持久对象上   相同的标识符如果当前没有持久化实例   与会话相关联,它将被加载。返回持久性   实例。 如果给定的实例未保存,保存和。的副本   将它作为新的持久化实例返回。给定的实例   没有与会话相关联。此操作级联到   如果关联使用cascade =“merge”映射关联实例。

之后你也坚持传入ne,所以你最终得到了两个持久的NamedEntity个实例:一个由merge创建(复制)的实例和你明确持有的实例({ {1}})。

正确的解决方案是将ne重构为不包含save等类似代码的内容。

丑陋的快速解决方法是从if(!em.contains(ne.getNamedEntityGroup()))正文中删除不必要的em.persist(ne)。这将使事情有效,但会非常混乱(在if返回后传入的ne仍然是暂时的。

更好的快速解决方法是加载持久性save

NamedEntityGroup