2016-09-18 26 views
0

有一种我不明白的行为。Spring-Data:生成的值影响更新实体,而不是插入

我要像实体:

@Entity 
@EqualsAndHashCode(of={"name"}) 
@ToString(of={"name", "entityB"}) 
public class EntityA { 

    @Id 
    @GeneratedValue 
    @Getter 
    @Setter 
    private Long id; 

    @Getter 
    @Setter 
    @Column(nullable=false, unique=true) 
    private String name; 

    @Getter 
    @Setter 
    @ManyToOne(fetch=EAGER, cascade={PERSIST, MERGE}) 
    private EntityB entityB; 

} 

@ToString(of = { "name" }) 
@EqualsAndHashCode(of = { "name" }) 
@Entity 
class EntityB { 

    @Id 
    @GeneratedValue 
    @Getter 
    @Setter 
    private Long id; 

    @Getter 
    @Setter 
    @XmlAttribute 
    @Column(nullable=false, unique=true) 
    private String name; 
} 

和逻辑将数据插入到数据库:

@Component 
public class DatabaseInitializer implements InitializingBean { 
    @Autowired EntityARepository repository; // Spring-Data CrudRepository! 

    @Override 
    public void afterPropertiesSet() throws Exception { 
     final Set<EntityA> aEntities = createAEntities(); 
     repository.save(aEntities); 

     Iterator<EntityA> iterator = repository.findAll().iterator(); 
     while(iterator.hasNext()){ 
      System.out.println(iterator.next()); 
     } 
    } 

    private Set<EntityA> createAEntities() throws Exception { 
     Set<EntityA> aEntities = new HashSet<>(); 
     aEntities.add(getFirstEntityA()); 
     aEntities.add(getSecondEntityA()); 
     return aEntities; 
    } 

    private EntityA getFirstEntityA(){ 
     EntityA a = new EntityA(); 
     a.setId(1L); 
     a.setName("a-1"); 
     a.setEntityB(getFirstEntityB()); 
     return a; 
    } 

    private EntityA getSecondEntityA(){ 
     EntityA a = new EntityA(); 
     a.setId(2L); 
     a.setName("a-2"); 
     a.setEntityB(getFirstEntityB()); 
     return a; 
    } 

    // 

    private EntityB getFirstEntityB() { 
     EntityB b = new EntityB(); 
     b.setId(1l); 
     b.setName("b-1"); 
     return b; 
    } 

} 

当启动应用程序时,我得到以下的输出:

org.hibernate.SQL: select entitya0_.id as id1_0_1_, entitya0_.entityb_id as entityb_3_0_1_, entitya0_.name as name2_0_1_, entityb1_.id as id1_1_0_, entityb1_.name as name2_1_0_ from entitya entitya0_ left outer join entityb entityb1_ on entitya0_.entityb_id=entityb1_.id where entitya0_.id=? 
org.hibernate.SQL: select entityb0_.id as id1_1_0_, entityb0_.name as name2_1_0_ from entityb entityb0_ where entityb0_.id=? 
org.hibernate.SQL: insert into entityb (id, name) values (default, ?) 
org.hibernate.SQL: insert into entitya (id, entityb_id, name) values (default, ?, ?) 
org.hibernate.SQL: update entitya set entityb_id=?, name=? where id=? 

EntityA(name=a-1, entityB=EntityB(name=b-1)) 

由于你可以看到,它更新了entitya,而不是向db添加一个新行。

当我从两个实体中删除@GeneratedValue它的作品。

org.hibernate.SQL: select entitya0_.id as id1_0_1_, entitya0_.entityb_id as entityb_3_0_1_, entitya0_.name as name2_0_1_, entityb1_.id as id1_1_0_, entityb1_.name as name2_1_0_ from entitya entitya0_ left outer join entityb entityb1_ on entitya0_.entityb_id=entityb1_.id where entitya0_.id=? 
org.hibernate.SQL: select entityb0_.id as id1_1_0_, entityb0_.name as name2_1_0_ from entityb entityb0_ where entityb0_.id=? 
org.hibernate.SQL: select entitya0_.id as id1_0_1_, entitya0_.entityb_id as entityb_3_0_1_, entitya0_.name as name2_0_1_, entityb1_.id as id1_1_0_, entityb1_.name as name2_1_0_ from entitya entitya0_ left outer join entityb entityb1_ on entitya0_.entityb_id=entityb1_.id where entitya0_.id=? 
org.hibernate.SQL: insert into entityb (name, id) values (?, ?) 
org.hibernate.SQL: insert into entitya (entityb_id, name, id) values (?, ?, ?) 
org.hibernate.SQL: insert into entitya (entityb_id, name, id) values (?, ?, ?) 

EntityA(name=a-1, entityB=EntityB(name=b-1)) 
EntityA(name=a-2, entityB=EntityB(name=b-1)) 

当我想用ID发电机和实体的创建者删除SETID(...),我得到了一个HsqlExceptionNullPointerException

Caused by: org.hsqldb.HsqlException: java.lang.NullPointerException 
    at org.hsqldb.error.Error.error(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3] 
    at org.hsqldb.persist.RowStoreAVL.indexRow(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3] 
    at org.hsqldb.TransactionManager2PL.addInsertAction(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3] 
    at org.hsqldb.Session.addInsertAction(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3] 
    at org.hsqldb.Table.insertSingleRow(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3] 
    at org.hsqldb.StatementDML.insertRowSet(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3] 
    at org.hsqldb.StatementInsert.getResult(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3] 
    at org.hsqldb.StatementDMQL.execute(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3] 
    at org.hsqldb.Session.executeCompiledStatement(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3] 
    at org.hsqldb.Session.execute(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3] 
    ... 87 common frames omitted 
Caused by: java.lang.NullPointerException: null 
    at org.hsqldb.index.IndexAVLMemory.insert(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3] 
    ... 96 common frames omitted 

至少是我想的是,我不`吨需要给entityA一个标识符,它应该由它自己产生,我想至少有两个entitiesA。

+0

您可以请发布完整的堆栈跟踪吗?这可能有帮助。您还使用哪个版本的hsql? –

+0

另外,你可以删除'entityB'的'name'字段上的'unique' constants,并且除去对setId(...)的调用吗?我怀疑它是否为EntityA插入的第二次插入抛出ConstraintViolated异常。 –

回答

1

至少我想要的是我不需要给entityA一个标识符,它应该由它自己生成,并且我至少需要两个entitiesA。

我相信你不想为entityA和entityB手动分配id。如果是这样,你可以删除a.setId(1L)a.setId(2L)b.setId(1l)并尝试。

由于您使用的是@GeneratedValue,因此它会使用统一格式GenerationType.AUTO并为您填充ID。

另一方面,repository.save(...)是一种双重方法,它决定是否已经存在具有相同ID的实体。如果具有该标识的实体已经存在于数据库中,它将发出更新语句,否则它会发出插入语句。

在你的情况下,因为你使用的entityA实例的ID相同的entityB实例,我相信它将它视为一个现有的实体,更新语句将获得第二个entityA而不是创建新的实体。

UPDATE

我已经通过删除调用setId(...)两个EntityAEntityB它导致以下错误,因为unique=true上存在的EntityBname场尝试了代码。

Hibernate: insert into entityb (id, name) values (null, ?) 
Hibernate: insert into entitya (id, entityb_id, name) values (null, ?, ?) 
Hibernate: insert into entityb (id, name) values (null, ?) 
2016-09-19 18:11:28.960 WARN 10956 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 23505, SQLState: 23505 
2016-09-19 18:11:28.960 ERROR 10956 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : Unique index or primary key violation: "UK_Q9VYNGA314JSWU3TEA1LCF3P4_INDEX_C ON PUBLIC.ENTITYB(NAME) VALUES ('b-1', 1)"; SQL statement: 
insert into entityb (id, name) values (null, ?) [23505-190] 
2016-09-19 18:11:28.990 ERROR 10956 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["UK_Q9VYNGA314JSWU3TEA1LCF3P4_INDEX_C ON PUBLIC.ENTITYB(NAME) VALUES ('b-1', 1)"; SQL statement: 
insert into entityb (id, name) values (null, ?) [23505-190]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause 

org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "UK_Q9VYNGA314JSWU3TEA1LCF3P4_INDEX_C ON PUBLIC.ENTITYB(NAME) VALUES ('b-1', 1)"; SQL statement: 
insert into entityb (id, name) values (null, ?) [23505-190] 

去除unique=true后,结果是创造了两个EntityA情况下,如预期

Hibernate: insert into entityb (id, name) values (null, ?) 
Hibernate: insert into entitya (id, entityb_id, name) values (null, ?, ?) 
Hibernate: insert into entityb (id, name) values (null, ?) 
Hibernate: insert into entitya (id, entityb_id, name) values (null, ?, ?) 
Hibernate: select entitya0_.id as id1_3_, entitya0_.entityb_id as entityb_3_3_, entitya0_.name as name2_3_ from entitya entitya0_ 
EntityA [id=1, name=a-2, entityB=EntityB [id=1, name=b-1]] 
EntityA [id=2, name=a-1, entityB=EntityB [id=2, name=b-1]] 

所以,你可能要对entityBname字段中删除唯一约束,除去所呼叫to SETID测试沿(...)`方法。

仅供参考,我已经使用h2数据库进行测试。

+0

谢谢你的回复。当我删除a.setId(1L)时,我成为NullPointException,请参阅上面的问题。 –