在hibernate插入/更新查询中使用sysdate

时间:2013-09-27 23:34:29

标签: java sql oracle hibernate orm

我有一个类型为javax.persistence.Query的对象,其中有一个原生的PL / SQL查询(对于Oracle),如:

BEGIN
  merge into account t 
  using dual 
  ON (t.account_id = '1') 
  WHEN MATCHED THEN 
    update  set name=?, updated_date=? where account_id=? 
  WHEN NOT MATCHED THEN 
    insert  (name, account_id, created_date) values (?, ?, ?);
  COMMIT;
END;

我还有一个上面的位置参数列表,如下所示:     'some-name','01 / 01/2013 00:00:00','1'

问题是我想用sysdate替换updated_date / created_date的参数,以便我的最终go-to-DB查询如下所示:

BEGIN
  merge into account t 
  using dual 
  ON (t.account_id = '1') 
  WHEN MATCHED THEN 
    update  set name=?, updated_date=sysdate where account_id=? 
  WHEN NOT MATCHED THEN 
    insert  (name, account_id, created_date) values (?, sysdate, ?);
  COMMIT;
END;

但是,如果我将其中一个位置参数指定为'sysdate',那么Hibernate将字面上的字符串视为字符串,我会收到错误。 我怎么告诉Hibernate我想指定关键字sysdate而不是字符串'sysdate'?

由于某种原因,我们无法使用触发器或JVM日期(为简单起见省略了详细信息)

//在Martin的回复后更新

嗨,马丁,谢谢你的回答。

我看到你建议的代码,但无法做出任何改变。 很可能有一些我遗失的小作品,如果你可以帮助我的话会很棒。 我将发布相关的代码部分,以显示我所看到的内容。

public class PostgresUUIDType extends AbstractSingleColumnStandardBasicType<UUID> 
{
    public static final PostgresUUIDType INSTANCE = new PostgresUUIDType();

    public PostgresUUIDType() {
        super( PostgresUUIDSqlTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE );
    }
}


// which calls
public AbstractSingleColumnStandardBasicType(SqlTypeDescriptor sqlTypeDescriptor, JavaTypeDescriptor<T> javaTypeDescriptor) {
        super( sqlTypeDescriptor, javaTypeDescriptor );
}


// which calls
public AbstractStandardBasicType(SqlTypeDescriptor sqlTypeDescriptor, JavaTypeDescriptor<T> javaTypeDescriptor) {
        this.sqlTypeDescriptor = sqlTypeDescriptor;
        this.javaTypeDescriptor = javaTypeDescriptor;
}


// And the BasicTypeRegistry looks like this:

class BasicTypeRegistry {

    public BasicTypeRegistry() {
        register( BooleanType.INSTANCE );
        register( NumericBooleanType.INSTANCE );
        register( TrueFalseType.INSTANCE );
        ...
    }


    void register(BasicType type) {
        for ( String key : type.getRegistrationKeys() ) {
            final Type old = registry.put( key, type );
        }
    }

}

你能帮我把日期联系起来吗? 非常感谢你的帮助!!

3 个答案:

答案 0 :(得分:0)

要控制hibernate理解给定参数对象的方式,它使用BasicTypeRegistry。看看这个类:org.hibernate.type.PostgresUUIDType它增加了对特殊postgres类型的支持。您甚至可以通过查看org.hibernate.type.BasicTypeRegistry的构造函数来查找基本类型的更多示例。它包含hibernate映射的所有BasicType。

通过创建自己的BasicType并使用关键字的自定义对象表示,如Sysdate甚至新的OracleKeyword(“sysdate”)作为查询的参数,Hibernate将使用您的BasicType实现将其映射到SQL。所以现在你的BasicType实现让你完全控制最终结果(SQL)的样子。

请注意,在创建会话工厂configuration.getTypeResolver().registerTypeOverride(...)之前,您需要将基本类型添加到类型解析程序。

<强>更新

您的想法是,使用BasicType,您可以指定直接写出的实际SQL文本。它有点像黑客,因为这个值实际上是你写的东西。

关键部分是:

 public static class PostgresUUIDSqlTypeDescriptor implements SqlTypeDescriptor {
    public static final PostgresUUIDSqlTypeDescriptor INSTANCE = new PostgresUUIDSqlTypeDescriptor();

    public int getSqlType() {
        // ugh
        return Types.OTHER;
    }

请参阅Types.OTHER。在getBinder方法中,您可以直接控制SQL。可悲的是,我只记得这是我们几年前去过的方式。所以我试着概括一下 - 要注意,为了找到这个有用的你可以添加一些额外的研究:

public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
        return new BasicBinder<X>( javaTypeDescriptor, this ) {
            @Override
            protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
                st.setObject( index, javaTypeDescriptor.unwrap( value, UUID.class, options ), getSqlType() );
            }
        };
    }

这是getBinder方法。在这里,您可以看到类型提供的基本绑定器的doBind方法。在doBind方法中,您将获得预准备语句,X是您映射的值,int是您的参数值应该应用于的索引。

此时您还可以控制设置参数的内容和方式。如果我是正确的,您可以引用基础数据库的关键字或函数作为参数值。因此,使用这种方式,您现在可以回退到jdbc并测试是否可以将sysdate指定为参数值。因此,如果你在JDBC中使用它,你可以使用基本类型来使用hibernate。

答案 1 :(得分:0)

在这里,我找到了一种更好的方法来做你想做的事。使用EnhancedUserType,您可以控制写入的实际SQL以直接表示对象。查看objectToSQLString方法。

只需在此方法中返回“sysdate”,您的问题就应该解决了。为此编写简单的用户类型也非常简单。查看一些hibernate的示例用户类型,并搜索google以获取其他示例。

这是EnhancedUserType接口的原始代码,包括一些注释。

package org.hibernate.usertype;

 public interface EnhancedUserType extends UserType {
/**
 * Return an SQL literal representation of the value
 */
public String objectToSQLString(Object value);

/**
 * Return a string representation of this value, as it
 * should appear in an XML document
 */
public String toXMLString(Object value);
/**
 * Parse a string representation of this value, as it
 * appears in an XML document
 */
public Object fromXMLString(String xmlValue);
}

答案 2 :(得分:0)

我终于使用了@ColumnTransformer(write =“”),除了非常简单易用外,它的效果非常好。

它可以帮助您为每次hibernate执行插入或更新查询时插入到最终查询中的列选择一个写表达式。

参考链接:http://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/mapping.html#mapping-column-read-and-write