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

Java 在hibernate插入/更新查询中使用sysdate,java,sql,oracle,hibernate,orm,Java,Sql,Oracle,Hibernate,Orm,我有一个javax.persistence.Query类型的对象,其中有一个本地PL/SQL查询(针对Oracle),如: 我还有一个上面的位置参数列表,如下所示: “一些名字”,“2013年1月1日00:00:00”,“1” 问题是我想用sysdate替换updated_date/created_date的参数,这样我的最终go to DB查询如下所示: BEGIN merge into account t using dual ON (t.account_id = '1')

我有一个javax.persistence.Query类型的对象,其中有一个本地PL/SQL查询(针对Oracle),如:

我还有一个上面的位置参数列表,如下所示: “一些名字”,“2013年1月1日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日期(为了简单起见,省略了细节)

//马丁回应后更新

嗨,马丁,谢谢你的回答

我看到了您建议的代码,但无法从中得出任何结论。 很可能是我遗漏了一些小东西,如果你能帮我解决,那就太好了。 我将只发布相关的代码部分来展示我所看到的

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 );
        }
    }

}
公共类PostgresUidType扩展了AbstractSingleColumnSStandardBasicType
{
public static final postgresuidtype实例=new postgresuidtype();
公共PostgresUUIDType(){
super(PostgresUUIDSqlTypeDescriptor.INSTANCE、UUIDTypeDescriptor.INSTANCE);
}
}
//哪个叫
公共抽象SingleColumnStandardBasicType(SqlTypeDescriptor SqlTypeDescriptor,JavaTypeDescriptor JavaTypeDescriptor){
super(sqlTypeDescriptor、javaTypeDescriptor);
}
//哪个叫
公共抽象标准基本类型(SqlTypeDescriptor SqlTypeDescriptor,JavaTypeDescriptor JavaTypeDescriptor){
this.sqlTypeDescriptor=sqlTypeDescriptor;
this.javaTypeDescriptor=javaTypeDescriptor;
}
//基本类型注册表如下所示:
类基本类型注册表{
公共基本类型注册表(){
寄存器(BooleanType.INSTANCE);
寄存器(NumericBooleanType.INSTANCE);
寄存器(TrueFalseType.INSTANCE);
...
}
无效寄存器(基本类型){
for(字符串键:type.getRegistrationKeys()){
final Type old=registry.put(key,Type);
}
}
}
你能帮我把这里的日期联系起来吗?
非常感谢你的帮助

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

通过创建自己的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;
    }
请参阅类型。其他。在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() );
            }
        };
    }
public ValueBinder getBinder(最终JavaTypeDescriptor JavaTypeDescriptor){
返回新的BasicBinder(javaTypeDescriptor,this){
@凌驾
受保护的void doBind(PreparedStatement st、X值、int索引、WrapperOptions选项)抛出SQLException{
st.setObject(索引,javaTypeDescriptor.unwrap(值,UUID.class,选项),getSqlType());
}
};
}
这是getBinder方法。这里您可以看到该类型提供的基本绑定器的doBind方法。在doBind方法中,您得到准备好的语句,X是您映射的值,int是您的参数值预期应用到的索引


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

在这里,我找到了一种更好的方法来做你想做的事。使用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);
}

我终于使用了@ColumnTransformer(write=“”),它除了使用非常简单外,还工作得非常好

它可以帮助您为一个列选择一个写表达式,每当hibernate执行insert或update查询时,该列就会被插入到最终查询中


参考链接:

创建另一个类似的查询,其中sysdate是硬编码的,并调用此查询。嗨,马丁,我已经在问题中给出了我的回答。你能告诉我更多的细节吗?
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);
}