使用NHibernate, Oracle Clob/NClob無法插入、亂碼問題

來源:互聯網
上載者:User
伺服器Oracle 9i,用戶端Oracle 10g。

問題1:
NHibernate配置的Driver為NHibernate.Driver.OracleClientDriver,存入Clob、NClob欄位,值比較大時報錯,錯誤資訊
中文:ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值
英文:ORA-01461: can bind a LONG value only for insert into a LONG column

Google一下有很多人碰到這個問題,有人猜測是MS System.Data.OracleClient的一個Bug,方法是改用Oracle提供的Oracle.DataAccess。

解決方案:
下載安裝ODAC (Oracle Data Access Components),將NHibernate的Driver配置為NHibernate.Driver.OracleDataClientDriver,確保運行目錄下有Oracle.DataAccess.dll檔案。

問題2:
使用Oracle.DataAccess之後可以向一個NClob欄位中插入長文本,但文本有的情況下會變成亂碼。具體表現是輸入一些中文單詞,儲存後正常;輸入英文字元,儲存後正常;輸入一段中英文混雜的html,儲存後變成亂碼。
排除了伺服器、用戶端Oracle字元集設定問題。跟蹤NHibernate,在調用IDbCommand執行SQL語句時,參數中的值是正常的,因此排除了程式中對文本的編碼、解碼問題。

經過測試,使用下面的方式存入NClob的值不會變為亂碼:using Oracle.DataAccess.Client;

OracleConnection con = new OracleConnection("......");
con.Open();
OracleTransaction tran = con.BeginTransaction();
OracleCommand command = con.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = "update cms_template set temp_content=:p where temp_id=4";
OracleParameter param = command.CreateParameter();
param.ParameterName = ":p";
param.Value = this.textBox1.Text;
param.OracleDbType = OracleDbType.NClob;
command.Parameters.Add(param);
command.ExecuteNonQuery();
tran.Commit();
con.Close();

最關鍵的一句是將param.OracleDbType設定為OracleDbType.NClob,這樣Oracle.DataAccess就知道怎樣正確處理這個參數了。

NHibernate為了相容多資料庫,統一使用IDbParameter介面,對於NHibernate內部來講這個問題不好解決,我的方法是為CLob、NClob類型的屬性實現一個NHibernate.UserTypes.IUserType,在它的NullSafeSet方法中,修改IDbCommand中該欄位對應的IDbParameter的OracleDbType值,具體實現如下:public abstract class PatchForOracleLobField : IUserType
{
    public PatchForOracleLobField()
    {
    }

    public bool IsMutable
    {
        get { return true; }
    }

    public Type ReturnedType
    {
        get { return typeof(String); }
    }

    public SqlType[] SqlTypes
    {
        get { return new SqlType[] { new SqlType(DbType.String) }; }
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public new bool Equals(object x, object y)
    {
        return x == y;
    }

    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

    public object Disassemble(object value)
    {
        return DeepCopy(value);
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        return NHibernate.NHibernateUtil.StringClob.NullSafeGet(rs, names[0]);
    }

    public abstract void NullSafeSet(IDbCommand cmd, object value, int index);

    public object Replace(object original, object target, object owner)
    {
        return original;
    }
}

public class OracleClobField : PatchForOracleLobField
{
    public override void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        if (cmd is OracleCommand)
        {
            //CLob、NClob類型的欄位,存入中文時參數的OracleDbType必須設定為OracleDbType.Clob
            //否則會變成亂碼(Oracle 10g client環境)
            OracleParameter param = cmd.Parameters[index] as OracleParameter;
            if (param != null)
            {
                param.OracleDbType = OracleDbType.Clob;
                param.IsNullable = true;
            }
        }
        NHibernate.NHibernateUtil.StringClob.NullSafeSet(cmd, value, index);
    }
}

public class OracleNClobField : PatchForOracleLobField
{
    public override void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        if (cmd is OracleCommand)
        {
            //CLob、NClob類型的欄位,存入中文時參數的OracleDbType必須設定為OracleDbType.Clob
            //否則會變成亂碼(Oracle 10g client環境)
            OracleParameter param = cmd.Parameters[index] as OracleParameter;
            if (param != null)
            {
                param.OracleDbType = OracleDbType.NClob;
                param.IsNullable = true;
            }
        }
        NHibernate.NHibernateUtil.StringClob.NullSafeSet(cmd, value, index);
    }
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.