如何调用产生IEnumerable结果的函数?

时间:2017-12-09 17:28:37

标签: c# .net ienumerable yield

这是我的服务器端代码,它正在执行SQL存储过程并向我发送一些表结果。

public IEnumerable<IDataRecord> SomeFuncToCallDB(string pName, SqlParameter[] sqlParams, int commandTimeout = -1)
    {
        using (SqlConnection cn = GetNewConnection())
        using (SqlCommand cmd = cn.CreateCommand())
        {
            cmd.CommandText = pName;
            cmd.CommandType = CommandType.StoredProcedure;
            if (commandTimeout != -1) cmd.CommandTimeout = commandTimeout;
            if (sqlParams.Length > 0) 
            { 
                FixNullParams(sqlParams); 
                cmd.Parameters.AddRange(sqlParams); 
            }
            cn.Open();
            using (SqlDataReader dr = cmd.ExecuteReader())
            {
                while (dr.Read())
                {
                    yield return (IDataRecord)dr;
                }
                cn.Close();
            }
        }
    }

这是FixNullParams函数。

        private void FixNullParams(SqlParameter[] parameters)
    {
        foreach (SqlParameter p in parameters) if (p.Value == null) p.Value = DBNull.Value;
    }

什么时候,我这样称呼这个函数,

                List<SqlParameter> parameters = new List<SqlParameter>();
            parameters.Add(new SqlParameter("@AgencyFilter", "CountyPool"));
            IEnumerable<IDataRecord> dataFromDB = salesTax.SomeFuncToCallDB("[Data].[uspSomeSQLProc]", parameters.ToArray());

我收到以下异常。

“SqlParameter已包含在另一个SqlParameterCollection中。”

这发生在cmd.Parameters.AddRange行。

同时,如果我像这样调用相同的函数,

List<SqlParameter> parameters = new List<SqlParameter>();
            parameters.Add(new SqlParameter("@AgencyFilter", "CountyPool"));
            //IEnumerable<IDataRecord> dataFromDB = salesTax.SomeFuncToCallDB("[Data].[uspAgenciesSelect]", parameters.ToArray());
            foreach (IDataRecord eachRec in salesTax.SomeFuncToCallDB("[Data].[uspSomeSQLProc]", parameters.ToArray()))
            {
                int x = eachRec.FieldCount;

            }

然后它正常工作并循环遍历每条记录。

以下是我的问题。

  1. 调用此程序的正确方法是什么?
  2. 后来的电话怎么没有失败,但前者失败了?
  3. 如果我必须为此函数编写单元测试,我只想获得IEnumerable然后断言记录计数。但看起来,由于这个例外,我不能做这种测试。那么单元测试这个功能的正确方法是什么?

1 个答案:

答案 0 :(得分:0)

我想,我发现了问题。它是Visual Studio 2017中的调试行为

我能够创建一个小型测试数据库,然后创建一个简单的Windows应用程序来复制此问题。两个电话的行为都相同。

但是,当我执行逐行调试操作时,此异常会进入,如下面的快照所示。

enter image description here

对于好奇的用户,我在这里添加了完整的源代码。

$(document).ready(function () {
    $('#add-new-button').on('click',function(){
        var rData = [
            test1,
            test1,
            '<a href="#" data-href="' + response.result[0].id + '" class="update">Update</a>',
            '<a href="#" data-href="' + response.result[0].id + '" class="delete">Delete</a>'
        ];
         $('#dataTable').DataTable().row.add(rData).draw(false);
    });

   $('#dataTable').on('click', '.update', function () {
        var pageParamTable = $('#dataTable').DataTable();
        var tableRow = pageParamTable.row($(this).parents('tr'));
        var rData = [
            test1,
            test1,
            '<a href="#" data-href="' + response.result[0].id + '" class="update">Update</a>',
            '<a href="#" data-href="' + response.result[0].id + '" class="delete">Delete</a>'
        ];
        pageParamTable
                .row( tableRow )
                .data(rData)
                .draw();
    });
    $('#dataTable').on('click', '.delete', function () {
       var pageParamTable = $('#dataTable').DataTable();
        var tableRow = pageParamTable.row($(this).parents('tr'));
        pageParamTable.row( tableRow ).remove().draw();
    });
});

这是样本测试数据。

enter image description here

这是存储过程的SQL脚本。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Iterator
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            List<SqlParameter> parameters = new List<SqlParameter>();
            parameters.Add(new SqlParameter("@hobbyName", "Coding"));
            IEnumerable<IDataRecord> dataFromDB = GetUserInfo("dbo.GetUserBasedOnHobby", parameters.ToArray());
            int totalCount = dataFromDB.Count();
            MessageBox.Show("Total count : " + totalCount.ToString());
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error : " + ex.ToString());
        }
    }

    private void button2_Click(object sender, EventArgs e)
    {
        try
        {
            List<SqlParameter> parameters = new List<SqlParameter>();
            parameters.Add(new SqlParameter("@hobbyName", "Coding"));
            List<IDataRecord> allRecs = new List<IDataRecord>();
            foreach (IDataRecord eachRec in GetUserInfo("dbo.GetUserBasedOnHobby", parameters.ToArray()))
            {
                allRecs.Add(eachRec);
            }
            int totalCount = allRecs.Count();
            MessageBox.Show("Total count : " + totalCount.ToString());
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error : " + ex.ToString());
        }
    }

    private void FixNullParams(SqlParameter[] parameters)
    {
        foreach (SqlParameter p in parameters) if (p.Value == null) p.Value = DBNull.Value;
    }

    public IEnumerable<IDataRecord> GetUserInfo(string pName, SqlParameter[] sqlParams, int commandTimeout = -1)
    {
        using (SqlConnection cn = new SqlConnection("Data Source=MACHINE2;Initial Catalog=TestDB;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"))
        using (SqlCommand cmd = cn.CreateCommand())
        {
            cmd.CommandText = pName;
            cmd.CommandType = CommandType.StoredProcedure;
            if (commandTimeout != -1) cmd.CommandTimeout = commandTimeout;
            if (sqlParams.Length > 0)
            {
                FixNullParams(sqlParams);
                cmd.Parameters.AddRange(sqlParams);
            }
            cn.Open();
            using (SqlDataReader dr = cmd.ExecuteReader())
            {
                while (dr.Read())
                {
                    yield return (IDataRecord)dr;
                }
                cn.Close();
            }
        }
    }


  }
}

感谢大家的意见和回应。它帮助我深入挖掘以发现问题。