有一种我不理解的行为。
我必须使用以下实体:
@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;
}
将数据插入db:
的逻辑@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-Generator并从entity-creator中移除setId(...),我会在NullPointerException
中获得HsqlException
。
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一个标识符,它应该由它自己生成,我想要至少两个实体A.
答案 0 :(得分:1)
至少我想要的是我不需要给entityA一个标识符,它应该由它自己生成,我想要至少两个实体A.
我相信您不想手动为entityA和entityB分配ID。如果是这样,您可以删除a.setId(1L)
,a.setId(2L)
和b.setId(1l)
并尝试。
当您使用@GeneratedValue
时,它会使用stragegy作为GenerationType.AUTO
并为您填充ID。
另一方面,repository.save(...)
是一种双重方法,它决定具有相同ID的实体是否已存在。如果具有该id的实体已存在于数据库中,则它会发出update语句,否则会发出insert语句。
在您的情况下,由于您正在使用同一个具有相同id的entityB实例,因此我认为它将它视为现有实体,为第二个entityA发出更新语句而不是创建新实体。
<强> 更新的 强>
我已尝试删除对setId(...)
和EntityA
上的EntityB
的调用,但导致跟踪错误,因为unique=true
出现在{name
上1}} EntityB
的字段。
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]]
因此,您可能希望删除name
的{{1}}字段上的唯一约束,并测试并删除调用entityB
setId(...)`方法。
仅供参考,我使用了h2数据库进行测试。