【问题标题】:Error: "The SqlParameter is already contained by another SqlParameterCollection" when adding a Parameter错误:添加参数时“SqlParameter 已被另一个 SqlParameterCollection 包含”
【发布时间】:2015-09-03 02:54:19
【问题描述】:

我有一些与我的 SQL 服务器交互的类似函数(选择、调用存储过程等),除了下面的一个之外,所有函数都可以工作。每个 SqlConnection 都包含在 using 块中,SqlCommand 也包含在 using 块中。

此代码在尝试添加 @LastUpdated 参数时失败。我尝试了一些我在其他帖子中看到的建议:cmd.Parameters.Clear(),使用包装等,但没有运气。当重复尝试在找到的位置设置相同的参数时,解决了一些具有相同错误的帖子。可能我错过了,但我已经看了几个小时,甚至清洁了眼镜。任何方向将不胜感激。

private void _AddCartItem(bool hasEventInCart, _EventCart cartContents, ref int cartItemId)
{
    using (SqlConnection sqlConnection = new SqlConnection(_striMISConnection))
    {
        sqlConnection.Open();

        using (SqlCommand cmd = sqlConnection.CreateCommand())
        {
            SqlParameter param = new SqlParameter();
            cmd.Parameters.Clear();

            // add/update CartItem
            if (hasEventInCart)
            {
                // Update item
                cmd.CommandText = "SProc2Insert @CartItemId, @ID, 'Event', @Created, @LastUpdated";
                param.ParameterName = "@CartItemId";
                param.Value = cartItemId;
                cmd.Parameters.Add(param);
            }
            else
            {
                // add item
                cmd.CommandText = "SProc2Update @ID, 'Event', @Created, @LastUpdated";
            }

            cmd.CommandType = CommandType.Text;

            param.ParameterName = "@Created";
            param.Value = DateTime.Now.ToString();
            cmd.Parameters.Add(param);

            param.ParameterName = "@LastUpdated";
            param.Value = DateTime.Now.ToString();
            **cmd.Parameters.Add(param);**

            param.ParameterName = "@ID";
            param.Value = this.ID;
            cmd.Parameters.Add(param);

            if (hasEventInCart)
            {
                cmd.ExecuteNonQuery(); // do the update
            }
            else
            {
                cartItemId = (int)cmd.ExecuteScalar();

                foreach (var currentCartEvent in cartContents.CartEvents)
                {
                    if (currentCartEvent.EventCode == this.EventCode)
                    {
                        currentCartEvent.CartItemID = cartItemId;
                    }
                }
            }
            cmd.Parameters.Clear();
        }
    }
}

【问题讨论】:

  • 您需要创建新的 SqlParameter 实例,而不是重复使用同一个。它们是通过引用传递的。你正在覆盖它。因此,当您再次调用 add 时,您正在尝试添加一个自从您更新第一个参数的名称以来已经存在的参数。它们是同一个对象。
  • 创建 SqlParameter 的新实例或使 IEnumerable 然后 cmd.Parameters.AddRange
  • 提示:添加参数和设置值可以在一条语句中完成:sqlCommand.Parameters.Add("@Filename", System.Data.SqlDbType.VarChar, 64).Value = "Foo";。添加outputreturnvalue 参数可以在单个语句中完成:sqlCommand.Parameters.Add("@Filename", System.Data.SqlDbType.VarChar, 64).Direction = System.Data.ParameterDirection.Output;。您将 DateTime 值作为字符串而不是 DateTime 或更合适的数据类型(DateDateTimeOffset、...)传递,这有点奇怪。
  • @HABO ...感谢您的快捷方式。这是函数的第一次传递。我会清理它并调整 DateTime 值。

标签: c# sql-server


【解决方案1】:

我也遇到了同样的问题,你可以用下面的代码解决:

if (SqlParams != null && SqlParams.Count > 0)
{ 
    foreach (SqlParameter spp in SqlParams )
    {
        SqlParameter nameParam = new SqlParameter(spp.ParameterName, spp.SqlValue);

        mycmd.Parameters.Add(nameParam);
    }
}

【讨论】:

    【解决方案2】:

    首先,如果您要调用存储过程,则需要将CommandType 设置为CommandType.StoredProcedure - 而不是Text

    cmd.CommandType = CommandType.StoredProcedure;
    

    只需使用存储过程名称作为您的命令查询:

    cmd.CommandText = "dbo.SProc2Update";
    

    其次,我不会只使用一个 SqlParameter 实例,而是一遍又一遍地添加它 - 我会直接使用 .Add() 方法 - 并且停止转换所有日期/是时候串起来了!使用他们拥有的适当本机数据类型 - DateTime - 并在您的 Parameters.Add() 调用中指定:

    cmd.Parameters.Add("@Created", SqlDbType.DateTime).Value = DateTime.Now;
    
    cmd.Parameters.Add("@LastUpdated", SqlDbType.DateTime).Value = DateTime.Now;
    

    【讨论】:

    • 他正在使用临时查询调用存储过程。他不能直接将CommandType 更改为StoredProcedure,作者需要删除参数列表。如果要更改命令类型,作者还需要将“事件”作为参数传递。
    • 感谢两位的回复。较早的回复确实解决了问题,但我们非常感谢您的建议。
    【解决方案3】:

    这就是我的工作方式:

            ILease lease = (ILease)_SqlParameterCollection.InitializeLifetimeService();
            if (lease.CurrentState == LeaseState.Initial)
            {
                lease.InitialLeaseTime = TimeSpan.FromMinutes(5);
                lease.SponsorshipTimeout = TimeSpan.FromMinutes(2);
                lease.RenewOnCallTime = TimeSpan.FromMinutes(2);
                lease.Renew(new TimeSpan(0, 5, 0));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-17
      • 1970-01-01
      • 2011-12-11
      • 2011-09-11
      • 1970-01-01
      • 2019-04-10
      • 2012-06-14
      • 1970-01-01
      相关资源
      最近更新 更多