準備sql
系統環境 xp+.net2.0+oracle9isass
表結構(因爲是測試,表結構隨便建了一張) XX session
字段名oracle |
類型app |
IDide |
VARCHAR2(70)測試 |
TESTui |
CLOBspa |
測試.net
方式1:直接將CLOB的值拼寫在SQL語句中。
代碼:
狀況分析:
當data的長度大於4000時報錯(ORA-01704:文字字符串過長),小於或等於4000時正常插入。
緣由分析:
之因此會出現長度大於4000時報錯,是由於Oracle中有SQL語句中兩個單引號之間的字符數不能大於4000的限制。'" + data + "' data在sql語句之間,當data的值大於4000個字節時就會報錯。
解決辦法:
這種方式比較棘手,但有更好的方式,下邊會講到。
方式2:採用參數形式。
代碼:
狀況分析:
採用這種方式可以正常插入。因此推薦用這種方式。
緣由分析:
無
解決辦法:
無
方式3:採用參數形式,可是參數類型寫爲OracleType. NVarChar
代碼:
狀況分析:
爲何要寫這種方式,由於這種方式和採用NHibernate的方式很類似,先看看在這種方式會產生什麼狀況。當data的字節數在0-2000之間時正常插入,大於4000時也正常插入,但在2000-4000時則失敗,報錯(ORA-01461:僅能夠插入LONG列的LONG值賦值)
緣由分析:
沒有采用對應的Oracle類型。
解決辦法:
採用OracleType.Clob
下邊採用NHibernate插入數據,NHibernate具體怎用不在本次討論範圍。
NHibernate採用的版本爲1.2.1.4000。
下邊大至把簡要配置寫下。
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</configSections>
<nhibernate>
<add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
<add key="hibernate.connection.driver_class" value="NHibernate.Driver.OracleClientDriver" />
<add key="hibernate.connection.isolation" value="ReadCommitted"/>
<add key="hibernate.dialect" value="NHibernate.Dialect.Oracle9Dialect" />
<add key="hibernate.connection.connection_string"
value="Data Source=Orcl_192.168.0.232;User ID =icqs_test;Password=icqs_test" />
<add key="show_sql" value="true" />
<add
key="hibernate.adonet.batch_size"
value="100"
/>
</nhibernate>
</configuration>
xx.cs
xx.hbm.xml
<?xml version="1.0" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Test.Enties" assembly="Test">
<class name="Xx" table="xx" lazy="true">
<id name="Id" column="id" type="String">
<generator class="assigned"/>
</id>
<property column="test" type="StringClob" name="Test" length="2147483647" />
</class>
</hibernate-mapping>
說明:
<add key="hibernate.connection.driver_class" value="NHibernate.Driver.OracleClientDriver" />這裏的驅動用的NHibernate.Driver.OracleClientDriver,實際上是對微軟的OracleClient的封裝啦,其實內部仍是調用微軟的OracleClient的東東。引用System.Data.OracleClient.dll便可OracleClient。
作好上邊的配置後,便有了如下的方式
方式4:採用NHibernate
代碼:
狀況分析:
當data的字節數在0-2000之間時正常插入,大於4000時也正常插入,但在2000-4000時則失敗,報錯(ORA-01461:僅能夠插入LONG列的LONG值賦值).狀況和方式3的狀況同樣。
緣由分析:
NHibernate在用OracleClient映射StringClob時,設置參數類型爲OracleType. NVarChar,致使插入有BUG。網上有人推測是OracleClient的BUG所致,理由是換用OracleDataAccess便可解決。
爲何說NHibernate將參數類型設置爲OracleType.NVarChar呢?看下邊
2. 在Test解決方案中添加NHibernate的項目引用。
通過上邊兩個步驟咱們就能夠跟蹤調試NHibernate了
當咱們跟進CommandSetBatchingBatcher時,能夠獲得如下信息(如圖中的調試信息)。CurrentBatch類型是OracleClientCommandSet,OracleClientCommandSet看源碼得知是對微軟的OracleCommandSet的封裝,由於這個類internal sealed class,因此咱們的程序裏是找不到這個類的,不過NHibernate經過反射使用了它的功能。OracleCommandSet可能用做批處理的,就是一次處理多個SQL語句的,不是太瞭解,誰知道請指教。
CommandSetBatchingBatcher的源碼
跟蹤CurrentBatch能夠看到
CommandText:
declare
type refcursortype is ref cursor;
begin
INSERT INTO z3 (test, id) VALUES (:p2, :p3);
:r1_4 := sql%rowcount;
end;
這裏的p2就是咱們的Clob類型字段的參數啦。
再看p2的OracleType是NVarChar,是否是有點明白啦,對了, 跟咱們3同樣,參數類型錯掉了。
解決辦法:
使用NHibernate的自定義類型,不是太會,幸虧網上有高人提供代碼,在此想高人致謝。這樣咱們經過自定義類型來設置正確的OracleType便可。在項目中添加兩個類。
PatchForOracleLobField.cs
OracleClobField.cs
而後在映射文件中修改類型便可。
Com.Dic.Icqs.Entities.Type.OracleClobField,Com.Dic.Icqs.Entities
修改前:
<property column="test" type="StringClob" name="Test" length="2147483647" />
修改後:
<property column="test" type="Test.type.OracleClobField, Test " name="Test" length="2147483647" />
Test.type.OracleClobField是類的完整名,Test 即OracleClobField所在的程序集。