Hibernate saveOrUpdate,update需要原始行的所有字段

3
我正在使用mysql和hibernate向一张表中插入和更新行。我使用了saveOrUpdate调用。现在,当我尝试更新表中的一行时,我会收到一个异常。异常指出我的列requestTime不能为空。显然是正确的,因为我已经将该列属性设置为NotNull。
我能够添加该行,但是当我用2个以上列的值来更新它时,我就会遇到这个异常。
我假设当我更新时,我需要从表中读取该行,然后更新整行。这是真的吗?我原本希望hibernate saveOrUpdate会替我完成这个过程。所以当我插入新行时,我有一个对象,该对象具有所有列的getter方法。但是当我更新时,我只有一个对象,该对象只有主键和新列的getter方法。
Transaction txD;
Session session;
session = currentSession();
txD = session.beginTransaction();
session.saveOrUpdate(dataStore);
txD.commit();

异常

749368 [Thread-2] DEBUG org.hibernate.internal.util.EntityPrinter  - com.mcruiseon.carpool.concrete.SubscribeProviderConcrete{acceptedTime=Mon Jul 30 03:39:23 UTC 2012, requestTime=null, subscriberIdentityHash=1218553253, requestIdentity=167093126, subscribedProviderHash=-284086361, isAccepted=true}
749375 [Thread-2] DEBUG org.hibernate.SQL  - update carPoolSubscribedProvider set subscriberIdentityHash=?, requestTime=?, subscribedProviderHash=?, isAccepted=?, acceptedTime=? where requestIdentity=?
749398 [Thread-2] DEBUG org.hibernate.engine.jdbc.spi.SqlExceptionHelper  - Column 'requestTime' cannot be null [n/a]
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'requestTime' cannot be null

选择*从carPoolSubscribedProvider

+-----------------+------------------------+---------------------+------------------------+------------+--------------+
| requestIdentity | subscriberIdentityHash | requestTime         | subscribedProviderHash | isAccepted | acceptedTime |
+-----------------+------------------------+---------------------+------------------------+------------+--------------+
| 167093126       | -284086361             | 2012-07-27 16:13:19 | 1218553253             |          0 | NULL         |
+-----------------+------------------------+---------------------+------------------------+------------+--------------+

编辑:

| carPoolSubscribedProvider | CREATE TABLE `carPoolSubscribedProvider` (
  `requestIdentity` varchar(50) NOT NULL DEFAULT '',
  `subscriberIdentityHash` varchar(100) NOT NULL,
  `requestTime` datetime NOT NULL,
  `subscribedProviderHash` varchar(100) DEFAULT NULL,
  `isAccepted` tinyint(1) DEFAULT '0',
  `acceptedTime` datetime DEFAULT NULL,
  PRIMARY KEY (`requestIdentity`),

我需要为更新和插入编写不同的代码流吗?例如 if (update) { row=getColumn(primaryKey), appendValues(row, newValues) } else insert ? - Siddharth
3个回答

2
Hibernate无法确定您希望如何处理空值属性。它无法区分以下情况:
  1. 某些属性为null->应在数据库中设置为null
  2. 某些属性为null->不应更新此类属性。
将先前非空的属性的值设置为null意味着属性的值应更改。
如果您希望使某个列永远不成为更新语句的一部分,则可以在@Column注释中设置updatable属性为false。根据文档,它定义为:列是否包含在持久性提供程序生成的SQL UPDATE语句中

1
我能否让Hibernate在更新时忽略空列的值? - Siddharth
至少我不知道如何在空值的情况下忽略它。如果适用的话,您可以使其永远不成为更新的一部分。 - Mikko Maunu

1

如果您编写表定义,将会更容易。

对于非空列,有两种情况:

  1. 您有一个“默认值”。
 
    create table t1
    (
        id integer not null,
        column1 char not null default 'Y',
        column2 date not null default sysdate,
        column3 varchar2(30) not null default user,
        intcol integer not null default 12
    );

如果您在INSERT或UPDATE中未指定这些列,Oracle会自动将默认值放入表中。

  1. 没有“默认值”。
    create table t1
    (
        id integer not null,
        column1 char not null,
        column2 date not null ,
        column3 varchar2(30) not null,
        intcol integer default 12
    );

如果您在INSERT或UPDATE中未指定这些列,Oracle会自动抛出错误消息。

这是关于数据库中非空的理论,让我们来看看Hibernate:

您可以在列注释中放置类似于以下内容的内容:

 insert="false", update="false"

然后数据库将使用默认值,但如果在您的表定义中未指定默认值,则该字段的值应始终为非空。

编辑:

所以我现在看到你有3个“NOT NULL”列。 对于具有定义默认值“requestIdentity”的列,您可以使用动态更新或动态插入:http://www.mkyong.com/hibernate/hibernate-dynamic-update-attribute-example/

但对于其余的列,您必须将值放入变量中:

private Date requestTime = new Date();

private String subscriberIdentityHash = "someDefaultHashHere";

谢谢,我已经编辑了问题并提供了表定义,我应该把注释放在哪里? - Siddharth

0

oUp = 更新后带有空字段的行 & oDb = 在更新时从数据库中获取的行

public static <T> T updateChanges(T oDb, T oUp) {
    try {
        java.lang.reflect.Field[] fields = oDb.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.get(oUp) != null) {
                field.set(oDb, field.get(oUp));
            }
        }
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return oDb;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接