认父亲的DbParameter!!

昨日,写下了类似下面的代码:

 

         // 定义两个参数
         OleDbParameter[] param  =   {
                                         
new OleDbParameter("@Name", OleDbType.VarChar, 30{ Value = "小王" },
                                         
new OleDbParameter("@Id", OleDbType.Integer) { Value = 1 }
                                     }
;
        
// 执行判断是否存在
         ExecuteCommandText( " SELECT * FROM [User] WHERE [Name]=@Name AND [Id]<>@Id " , param);

        
// 执行更新操作
         ExecuteCommandText( " UPDATE [User] SET [Name]=@Name WHRERE [Id]=@Id " , param);


        
/**/ /// <summary>
        
/// 执行SQL命令
         
/// </summary>
        
/// <param name="commandText"></param>
        
/// <param name="pars"></param>

         public   static   void  ExecuteCommandText( string  commandText,  params  OleDbParameter[] pars)
        
{
            
//以下是演示代码
            using (OleDbCommand command = new OleDbCommand())
            
{
                command.Parameters.AddRange(pars);
                
//执行操作,演示所以不处理
                
//command.ExecuteNonQuery();
            }

        }

 

上面的两个ExecuteCommandText操作,看起来应该是没有问题的,可是运行后却发现在第二处的ExecuteCommandText操作中会抛出一个错误,类似如下提示:

另一个 OleDbParameterCollection 中已包含 OleDbParameter。

怎么回事??参数被包含了?从代码中可知,参数第一次运行时,参数却实是被包含到了第一个ExecuteCommandText里的command对象中的Parameters集合,可是已运行完了啊?为什么第二次还被限制不允许使用了?

只好,祭起"Reflector",根据错误追踪到System.Data.OleDbParameterCollection的Add(object value)方法,其代码如下:

[EditorBrowsable(EditorBrowsableState.Never)]
public   override   int  Add( object  value)
{
    
this.OnChange();
    
this.ValidateType(value);
    
this.Validate(-1, value);
    
this.InnerList.Add((OleDbParameter) value);
    
return (this.Count - 1);
}


 

 OnChange与ValidateType无错,所以不看,继续追进Validate(-1,value)方法,看其里面如何.Validate函数代码如下:

private   void  Validate( int  index,  object  value)
{
    
if (value == null)
    
{
        
throw ADP.ParameterNull("value"this, ItemType);
    }

    
object obj2 = ((OleDbParameter) value).CompareExchangeParent(thisnull);
    
if (obj2 != null)
    
{
        
if (this != obj2)
        
{
            
throw ADP.ParametersIsNotParent(ItemType, this);
        }

        
if (index != this.IndexOf(value))
        
{
            
throw ADP.ParametersIsParent(ItemType, this);
        }

    }

    
//这里的代码跟题无关,所以我删除了.//
}


 

嗯,重点是在"object obj2 = ((OleDbParameter) value).CompareExchangeParent(this, null);"这句话,到底这里是用于做什么的呢?继续追进去看看:

internal   object  CompareExchangeParent( object  value,  object  comparand)
{
    
object obj2 = this._parent;
    
if (comparand == obj2)
    
{
        
this._parent = value;
    }

    
return obj2;
}

此函数是在System.Data.OleDb.OleDbParameter里的,看到"this._parent=value"这段语句,发现问题所在了吧???如果还不清楚,那我把问题整理一次.

开头的代码分别执行了两次ExecuteCommandText,所以共有两个OleDbCommand对象,为了好说清问题我把它们命名为"CommandA"和"CommandB".

当第一次执行ExecuteCommandText操作时,也即是CommandA对象执行语句命令,当将param数组里的各参数都加入到CommandA的Parameters集合时,根据上面的代码流程,最终会执行到"CompareExchangeParent"方法,此时各参数的_parent是null,也即还没有父亲存在.所以会执行"this._parent=value",而此时的value则为CommandA.Parameters集合对象(this),也即各参数都把CommandA.Parameters认作了父亲.

而当第二次执行ExecuteCommandText操作时,也即是CommandB对象执行语句命令.当再次把param数组里的各参数都加入到CommandB的Parameters集合时,此时在"CompareExchangeParent"方法里,因各参数的_parent因为第一次的执行,所以都已有父亲存在,也就导致不会再运行this._parent=value语句(有父亲了,当然不再重新认人为父了-_-#).从而导致将会运行"Validate"函数里的这句判断:

         if  ( this   !=  obj2)
        
{
            
throw ADP.ParametersIsNotParent(ItemType, this);
        }

而此时this是CommandB.Parameters对象,而obj2是当前参数的父亲,也就是CommandA.Parameters.从而打架现象出现.系统抛出错误异常了.......

问题所在知道了,所以我们就要考虑怎么解决掉它.也就是让参数重新认父!!(呵呵,有点狠)

_parent参数是private的,所以我们是操作不了的.所以我们搜索一下看看有哪里引用了此变量的(不会搜索?在Reflector的左边树里找到它,右击它,选"Analyze",此时右下角就会出来一个区域,展开"Used By"节点就知道有哪些地方使用过它了).发现有一个"ResetParent()"函数,如下代码:

internal   void  ResetParent()
{
    
this._parent = null;
}


嗯嗯,高兴ING,执行这个函数后我们的参数就可以重新认父了..可是它却是internal的,我们调用不了,咋办?唉,真想骂微软*$@#$!!只好继续搜索,看有哪些地方引用了"ResetParent()"函数,此时亮点出现,我们在"System.Data.OleDb.OleDbParameterCollection"里发现有一个公共的(public)方法"Clear()",题头的问题终于可以解决了.将ExecuteCommandText函数更改为如下:

         /**/ /// <summary>
        
/// 执行SQL命令
        
/// </summary>
        
/// <param name="commandText"></param>
        
/// <param name="pars"></param>

         public   static   void  ExecuteCommandText( string  commandText,  params  OleDbParameter[] pars)
        
{
            
//以下是演示代码
            using (OleDbCommand command = new OleDbCommand())
            
{
                command.Parameters.AddRange(pars);
                
//执行操作,演示所以不处理
                
//command.ExecuteNonQuery();

                
//这句很重要,不清参数就不能再被其它Command使用了-_-#
                command.Parameters.Clear();
            }

        }

 

更改后运行代码,嗯,世界清静了,不会再有"父亲打架"的现象出现了......

PS:
最后还是要骂一下老微.这么重要的"认亲"行为,为什么在IDbCommand的Dispose()方法里不Clear一下呢??如果忘记Clear了,那参数使用过一次后就只能被抛弃了吗?!!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值