Hibernate 使用合并但不持久时的约束冲突(非NULL)
我在使用JPA时遇到了一些意想不到的行为 在我的数据模型中,我有两个实体,Hibernate 使用合并但不持久时的约束冲突(非NULL),hibernate,jpa,entitymanager,Hibernate,Jpa,Entitymanager,我在使用JPA时遇到了一些意想不到的行为 在我的数据模型中,我有两个实体,Foo和BarFoos和Bars实际上有一种多对多的关系——但是Bar在Foo中出现的每一个Bar都包含额外的信息,这导致我们避免使用简单的可连接方法。因此,我们使用另一个实体FooBar,来表示Foo中出现的Bar。这里有一些例子。(请注意,除了关系成员/方法之外,我省略了所有内容) 通过启用额外的日志输出,我发现,当使用merge时,它实际上试图插入FooBar两次!以下是使用merge时的相关日志输出: 1609 [
Foo
和Bar
Foo
s和Bar
s实际上有一种多对多的关系——但是Bar
在Foo
中出现的每一个Bar
都包含额外的信息,这导致我们避免使用简单的可连接方法。因此,我们使用另一个实体FooBar
,来表示Foo
中出现的Bar
。这里有一些例子。(请注意,除了关系成员/方法之外,我省略了所有内容)
通过启用额外的日志输出,我发现,当使用merge
时,它实际上试图插入FooBar
两次!以下是使用merge
时的相关日志输出:
1609 [main] INFO my.example.Example - ============ MERGE ============
1610 [main] DEBUG org.hibernate.SQL -
insert
into
FooBar
(id, bar, foo, info, version)
values
(default, ?, ?, ?, ?)
1610 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - 1
1610 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - 1
1610 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [3] as [VARCHAR] - <null>
1610 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [BIGINT] - 0
1612 [main] DEBUG org.hibernate.SQL -
insert
into
FooBar
(id, bar, foo, info, version)
values
(default, ?, ?, ?, ?)
1612 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - <null>
1613 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - <null>
1613 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [3] as [VARCHAR] - <null>
1613 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [BIGINT] - 0
1614 [main] WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: -10, SQLState: 23502
1614 [main] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - integrity constraint violation: NOT NULL check constraint; SYS_CT_10097 table: FOOBAR column: BAR
1616 [main] INFO my.example.Example - ===============================
出于其他几个原因,我们决定在DAO实现中使用merge
,我更愿意找到一种方法,使用merge
正确地完成这项工作。我希望你们中的一位能提供一些见解
最后,值得一提的是,我们的JPA提供程序是Hibernate——尽管您可以看到,在本例中我仅限于JPA注释。我的测试在HSQLDB中运行,而我们的生产代码使用PostgreSQL
谢谢
柯蒂斯
更新
我想我最终要做的是改变dao.createOrUpdate
(这就是使用merge
)的实现。上面没有包括的是Foo
、Bar
和FooBar
都提供了getId()
方法。因此,我想我要这样做:
public <T extends PersistentObject> T createOrUpdate(T object)
{
if ( null == object.getId() )
{
manager.persist(object);
return object;
}
return manager.merge(object);
}
public T createOrUpdate(T对象)
{
if(null==object.getId())
{
持久化(对象);
返回对象;
}
返回管理器。合并(对象);
}
(PersistentObject
是所有对象的通用接口)
1609 [main] INFO my.example.Example - ============ MERGE ============
1610 [main] DEBUG org.hibernate.SQL -
insert
into
FooBar
(id, bar, foo, info, version)
values
(default, ?, ?, ?, ?)
1610 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - 1
1610 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - 1
1610 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [3] as [VARCHAR] - <null>
1610 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [BIGINT] - 0
1612 [main] DEBUG org.hibernate.SQL -
insert
into
FooBar
(id, bar, foo, info, version)
values
(default, ?, ?, ?, ?)
1612 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - <null>
1613 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - <null>
1613 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [3] as [VARCHAR] - <null>
1613 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [BIGINT] - 0
1614 [main] WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: -10, SQLState: 23502
1614 [main] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - integrity constraint violation: NOT NULL check constraint; SYS_CT_10097 table: FOOBAR column: BAR
1616 [main] INFO my.example.Example - ===============================
1636 [main] INFO my.example.Example - ============ PERSIST ============
1636 [main] DEBUG org.hibernate.SQL -
insert
into
FooBar
(id, bar, foo, info, version)
values
(default, ?, ?, ?, ?)
1636 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - 2
1636 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - 2
1637 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [3] as [VARCHAR] - <null>
1637 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [BIGINT] - 0
1642 [main] DEBUG org.hibernate.SQL -
update
Foo
set
fooValue=?,
version=?
where
id=?
and version=?
1642 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - This is a foo value
1643 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - 1
1643 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [3] as [BIGINT] - 2
1643 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [BIGINT] - 0
1645 [main] DEBUG org.hibernate.SQL -
update
Bar
set
barValue=?,
version=?
where
id=?
and version=?
1646 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - This is a bar value
1646 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - 1
1646 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [3] as [BIGINT] - 2
1646 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [BIGINT] - 0
1646 [main] INFO my.example.Example - =================================
public <T extends PersistentObject> T createOrUpdate(T object)
{
if ( null == object.getId() )
{
manager.persist(object);
return object;
}
return manager.merge(object);
}