0

我有一个 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 );
        }
    }

}

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

4

3 回答 3

0

为了控制 hibernate 理解给定参数对象的方式,它使用 BasicTypeRegistry。看看这个类:org.hibernate.type.PostgresUUIDType它增加了对特殊 postgres 类型的支持。您甚至可以通过查看org.hibernate.type.BasicTypeRegistry. 它包含了hibernate映射的所有BasicTypes。

通过创建自己的 BasicType 并使用关键字的自定义对象表示,如 Sysdate 甚至 new 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 一起使用。

于 2013-09-28T09:27:58.860 回答
0

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

只需在此方法中返回“sysdate”即可解决您的问题。为此编写一个简单的用户类型也很简单。查看一些示例用户类型的 hibernate 并搜索 google 以获取更多示例。

这是增强用户类型接口的原始代码,包括一些注释。

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);
}
于 2013-10-06T10:50:58.790 回答
0

我终于使用了@ColumnTransformer(write=""),除了使用起来非常简单之外,它的效果非常好。

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

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

于 2013-10-22T20:09:12.737 回答