Hibernate 使用合并但不持久时的约束冲突(非NULL)

Hibernate 使用合并但不持久时的约束冲突(非NULL),hibernate,jpa,entitymanager,Hibernate,Jpa,Entitymanager,我在使用JPA时遇到了一些意想不到的行为 在我的数据模型中,我有两个实体,Foo和BarFoos和Bars实际上有一种多对多的关系——但是Bar在Foo中出现的每一个Bar都包含额外的信息,这导致我们避免使用简单的可连接方法。因此,我们使用另一个实体FooBar,来表示Foo中出现的Bar。这里有一些例子。(请注意,除了关系成员/方法之外,我省略了所有内容) 通过启用额外的日志输出,我发现,当使用merge时,它实际上试图插入FooBar两次!以下是使用merge时的相关日志输出: 1609 [

我在使用JPA时遇到了一些意想不到的行为

在我的数据模型中,我有两个实体,
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);
}