C# 将C SQL循环转换为Linq

C# 将C SQL循环转换为Linq,c#,sql,performance,linq,C#,Sql,Performance,Linq,我有一个名为ListTypes的列表,其中包含10种产品。下面的存储过程循环并获取每个循环产品的记录,并将其存储在列表ListID中。这正在扼杀我的sql盒,因为我有200多个用户整天不断地执行这项操作 我知道循环sql语句不是一个好的体系结构,但这是我使它工作的唯一方法。你知道我怎样才能做到这一点吗?也许是Linq语句,我从来没有用过这么大的Linq。多谢各位 protected void GetIds(string Type, string Sub) { LinkedIds.Clear

我有一个名为ListTypes的列表,其中包含10种产品。下面的存储过程循环并获取每个循环产品的记录,并将其存储在列表ListID中。这正在扼杀我的sql盒,因为我有200多个用户整天不断地执行这项操作

我知道循环sql语句不是一个好的体系结构,但这是我使它工作的唯一方法。你知道我怎样才能做到这一点吗?也许是Linq语句,我从来没有用过这么大的Linq。多谢各位

protected void GetIds(string Type, string Sub)
{
   LinkedIds.Clear();

  using (SqlConnection cs = new SqlConnection(connstr))
  {
    for (int x = 0; x < ListTypes.Count; x++)
    {
        cs.Open();
        SqlCommand select = new SqlCommand("spUI_LinkedIds", cs);
        select.CommandType = System.Data.CommandType.StoredProcedure;
        select.Parameters.AddWithValue("@Type", Type);
        select.Parameters.AddWithValue("@Sub", Sub);
        select.Parameters.AddWithValue("@TransId", ListTypes[x]);

        SqlDataReader dr = select.ExecuteReader();

        while (dr.Read())
        {
            ListIds.Add(Convert.ToInt32(dr["LinkedId"]));
        }
        cs.Close();
    }
  }
}

不是一个完整的答案,但这不适合在评论中。您至少可以更新现有代码以提高效率,如下所示:

protected List<int> GetIds(string Type, string Sub, IEnumerable<int> types)
{
    var result = new List<int>();

    using (SqlConnection cs = new SqlConnection(connstr))
    using (SqlCommand select = new SqlCommand("spUI_LinkedIds", cs))
    {
        select.CommandType = System.Data.CommandType.StoredProcedure;
        //Don't use AddWithValue! Be explicit about your DB types
        // I had to guess here. Replace with the actual types from your database
        select.Parameters.Add("@Type", SqlDBType.VarChar, 10).Value = Type;
        select.Parameters.Add("@Sub", SqlDbType.VarChar, 10).Value = Sub;
        var TransID = select.Parameters.Add("@TransId", SqlDbType.Int);
        cs.Open();

        foreach(int type in types)
        {
            TransID.Value = type;
            SqlDataReader dr = select.ExecuteReader();
            while (dr.Read())
            {
                result.Add((int)dr["LinkedId"]);
            }
        }
    }
    return result;
}
请注意,这种方式只能打开和关闭连接一次。通常在ADO.Net中,最好使用一个新的连接并为每个查询重新打开它。例外情况是在这样一个紧密的循环中。此外,循环内部唯一以这种方式更改的是单参数值。最后,最好设计不依赖于其他类状态的方法。此方法不再需要了解ListTypes和ListId类变量,这使得在其他方面对该方法进行更好的单元测试成为可能

同样,这不是一个完整的答案;这只是一个渐进的改进。您真正需要做的是编写另一个接受表值参数的存储过程,并基于现有存储过程中的查询来与表值参数联接,以便所有这些都可以放入单个SQL语句中。但是,在您共享存储过程代码之前,这是我能给您的最大帮助。

根据您的评论:
假设我有一个表,我必须从包含这10种产品的表中获取所有记录。我怎样才能得到所有这些产品?但这个数字是动态的

所以。。。为什么要使用存储过程呢?为什么不查询这个表呢

//If [Type] and [Sub] arguments are external inputs - as in, they come from a user request or something - they should be sanitized. (remove or escape '\' and apostrophe signs)
//create connection

string queryTmpl = "SELECT LinkedId FROM [yourTable] WHERE [TYPE] = '{0}' AND [SUB] = '{1}' AND [TRANSID] IN ({2})";
string query = string.Format(queryTmpl, Type, Sub, string.Join(", ", ListTypes);
SqlCommand select = new SqlCommand(query, cs);

//and so forth

要使用LINQtoSQL,需要将表映射到类。这将使查询更容易执行。

除了其他人编写的改进之外。 您可以将您的ID插入临时表,然后创建一个临时表

SELECT * from WhatEverTable WHERE transid in (select transid from #tempTable)
在MSSQL上,这工作得非常快


当您不使用MSSQL时,一个伟大的SQL Select with JOIN可能比Select IN快。您必须自己在DBMS上测试这些情况。

列表中总是有10项吗?@DavidG是动态的,所以可以是10、15或8项。为什么不将其放在数据集中,并将数据集对象分配给var对象??或者您也可以继续使用datareader,并将datareader对象分配给var object var dr=select.ExecuteReader;一个轻微的优化:在循环之外创建一次SqlCommand及其参数。然后在循环内部设置这些参数的值&execute。保持整个循环的连接处于打开状态。是否将ListTypes放入datatable中,并向需要表变量的sp传递一次?var TransID=选择参数。Add@TransId,SqlDbType.Int;这必须通过列表类型,数字总是变化的。我们的想法是,假设我有一个表,我必须从包含这10种产品的表中获取所有记录。我怎样才能得到所有这些产品?但是这个数字是动态的。@Apollo您会将列表类型作为参数传递,如果您继续阅读此代码,则会在每次迭代时从参数中为循环内的参数赋值,您确定关闭和打开连接有问题吗?我相信连接池会处理它。@SriramSakthivel正常情况下,它会处理。但是在一个紧密的循环中,这可能会更有效率。是的,让我们说我想获取所有的记录,包括汽车、自行车、车轮等。这可能是动态的,我需要将它们添加到列表中。我不想逐个循环并将它们存储到列表中。@Apollo这不会循环。这只需转到yourTable并返回WHERE子句为true的所有记录。然后,每个用户只向数据库发出一个请求,而不是ListTypes.length次数