Java 调用EntityManager.merge()时未设置Id

Java 调用EntityManager.merge()时未设置Id,java,hibernate,jpa,Java,Hibernate,Jpa,我在2个对象父对象和子对象之间有一个简单的单域关联,如下所示 母实体 @Entity public class Parent { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; @Version private Long version; @OneToMany(cascade

我在2个对象父对象和子对象之间有一个简单的单域关联,如下所示

母实体

    @Entity
    public class Parent {
     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;
     private String name;
     @Version
     private Long version;

      @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
      List<Child> children = new ArrayList<Child>();

      ....
    }
下面是我的测试,它加载一个现有的父级并添加一个子级,并在父级上调用EntityManager.merge()

    @Test
public void testParent(){
    Parent parent = (Parent) dao.loadParent(Parent.class, parentId);

    Child c = new Child();
    c.setName("c");

    parent.getChildren().add(c);

    dao.mergeEntity(parent);

    Assert.assertNotNull(c.getId());
}
测试id主键的断言失败。我看到记录与自动分配的主键一起正确插入数据库


所有my DAO调用都围绕事务进行包装,并根据需要进行传播。

由于您的id是由数据库设置的,JPA/Hibernate只能在SQL语句发送到数据库后进行设置。如果将Hibernate配置为显示sql语句或将日志更改为调试,则在调用
mergeEntity
时可能会看到没有发出sql语句

使测试工作的一种方法应该是在对子id进行断言之前添加em.flush()

管理事务的方式可能会有问题,但需要查看DAO的代码以及在单元测试中获取DAO引用的方式

EntityManager.merge(..)
获取一个实例并返回一个受管理的实例。如果是临时实例,则返回一个新实例(不修改原始实例)


因此,您的
mergeEntity(…)
方法应该
返回em.merge(entity)

您应该提供更多信息,这是spring还是ejb应用程序?您可以发布dao.mergeEntity(父)的代码吗?事务由spring处理下面是我的dao代码@Transactional(propagation=propagation.REQUIRED)公共对象mergeEntity(对象实体){return em.merge(entity);}@Transactional(propagation=propagation.REQUIRED)公共对象mergeEntity(对象实体){return em.merge(entity);}
    @Test
public void testParent(){
    Parent parent = (Parent) dao.loadParent(Parent.class, parentId);

    Child c = new Child();
    c.setName("c");

    parent.getChildren().add(c);

    dao.mergeEntity(parent);

    Assert.assertNotNull(c.getId());
}