因儲存過程引數型別不匹配而造成OleDbCommand的不可用(二) (轉)

amyz發表於2007-08-14
因儲存過程引數型別不匹配而造成OleDbCommand的不可用(二) (轉)[@more@]

(續 /develop/read_article.?id=18426">因過程引數型別不匹配而造成OleCommand的不可用一)

 

表格二,斷點二處的狀況

-:namespace prefix = o ns = "urn:schemas--com::office" />

comm

{System.Data.OleDb.OleDbCommand}

System.Data.OleDb.OleDbCommand

transaction

null

System.Data.OleDb.OleDbTransaction

cmdText

Test

string

cmdType

StoredProcedure

System.Data.CommandType

updatedRow

Both

System.Data.UpdateRowSource

commandTimeout

30

int

+

icommandText

{System.__Com}

System.Data.Common.UnsafeNativeMethods.ICommandText

handle_Accessor

1

int

commandBehavior

Default

System.Data.CommandBehavior

+

dbBindings

{System.Data.OleDb.DBBindings}

System.Data.OleDb.DBBindings

canceling

FALSE

bool

isPrepared

FALSE

bool

executeQuery

FALSE

bool

computedParameters

FALSE

bool

designTimeVisible

FALSE

bool

cmdState

0

int

recordsAffected

-1

int

CommandText

Test

string

CommandTimeout

30

int

CommandType

StoredProcedure

System.Data.CommandType

DesignTimeVisible

TRUE

bool

IsClosed

TRUE

bool

Transaction

null

System.Data.OleDb.OleDbTransaction

UpdatedRowSource

Both

System.Data.UpdateRowSource

由上面表格一和表格二可發現,在OleDbCommand第一次ExecuteNoQuery()時,將改變其內部icommandText,dbBindings,handle_Accessor等3個私有屬性。並且經過觀察發現,只有CommandText被賦予與原來不同的值時才把以上3個私有屬性的值恢復到原來的預設值(即icommandText=null,dbBindings=null,handle_Accessor=0)。

這時我們把上面的程式碼稍作修改,在第一個try塊裡給原本為儲存過程引數Age賦與一個不能轉換為整數值的字串:

using System;

using System.Data;

using System.Data.OleDb;

namespace testCommand

{

  class Class1

  {

  [STAThread]

  static void Main(string[] args)

  {

  OleDbConnection conn=new OleDbConnection("xxx");

  conn.Open();

  OleDbCommand comm=new OleDbCommand("Test",conn);

  comm.CommandType=CommandType.StoredProcedure;

  OleDbCommandBuilder.DeriveParameters(comm);

  try

  {

  comm.Parameters["Name"].Value="my name";

  comm.Parameters["Age"].Value=(object)”aa”;

  comm.ExecuteNonQuery();  //斷點三,此處記憶體狀況見表一

  }

  catch(Exception err)

  {

    Console.WriteLine(

  err.TargetSite+" -- "+err.StackTrace+" -- "+

  err.Source+" -- "+err.Message+" -- "+

  err.GetType().ToString());

  }

 

  //TODO: 增加對OleDbCommand進行修復的語句

 

  try

  {

  comm.Parameters["Name"].Value="my name";

  comm.Parameters["Age"].Value=(object)11;

  comm.ExecuteNonQuery();  //斷點四

  }

  catch(Exception err)

  {

  Console.WriteLine(

  err.TargetSite+" -- "+err.StackTrace+" -- "+

  err.Source+" -- "+err.Message+" -- "+

  err.GetType().ToString());

  }

  conn.Close();

  }

  }

}

這時,在執行到斷點三時會丟擲System.FormatException的例外,再觀察斷點四處的記憶體狀況:

+

icommandText

{System.__ComObject}

System.Data.Common.UnsafeNativeMethods.ICommandText

handle_Accessor

0

int

dbBindings

null

System.Data.OleDb.DBBindings

CommandText

Test

string

CommandType

StoredProcedure

System.Data.CommandType

發現icommandText,dbBindings,handle_Accessor三個私有屬性只有icommandText被修改。程式在往下執行,我們得到System.Data.OleDb.OleDbException例外,提示Command text was not set for the command object。但是此時的CommandText及CommandType都為有效值。可見ExecuteNoQuery()在執行命令時依賴於icommandText,dbBindings和handle_Accessor。而之前的第一個try塊,由於儲存過程引數型別的不匹配丟擲異常,使ExecuteNoQuery()執行和只有icommandText一個私有屬性發生改變,此時雖然CommandText和CommandType還是原來正確的值,但由於dbBindings和handle_Accessor 沒有被正確賦值而丟擲認為沒有命令文字的例外。

於是我們可以假設OleDbCommand在執行時是判斷icommandText屬性是否為空值再根據命令文字生成私有屬性的時候,如果是則分析CommandText的值修改icommandText,dbBindings,handle_Accessor等3個私有屬性;否則直接時用icommandText,dbBindings,handle_Accessor已有的值。如果CommandText的值發生改變,OleDbCommand重設icommandText,dbBindings,handle_Accessor的值,在下一次執行ExecuteNoQuery() 時根據命令文字重新生成私有屬性的值。

這樣,由儲存過程引數不匹配而引起的OleDbCommand不可用的問題就迎刃而解了。只需要在兩個try塊間的加入以下語句 即可:

comm.CommandText=””;

comm.CommandText=”Test”;

以上對於OleDbCommand的討論居於.Net 1.0

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-956641/,如需轉載,請註明出處,否則將追究法律責任。

相關文章