如何在 List<> 中捕获此存储过程的结果?

How can I capture the results of this Stored Procedure in a List<>?

我已经为此苦苦挣扎了至少 3 个小时,而且我对 C# 还有些陌生,尤其是 return 从 SQL 服务器中的存储过程中获取多行。

我想return一个存储过程的结果:

create procedure ingredientNames_givenDishId
    @dishid inT
AS
    SELECT 
        a.ingredientname --given dish id, return ingredientnames     
    FROM 
        dbo.purple_ingredients a 
    JOIN 
        dbo.purple_dish_ingredients b ON a.ingredientid = b.ingredientid
    WHERE
        b.dishid = @dishid

这是我在 SQL 服务器中执行相同程序时的结果,其中 10 为 dishid:

我的 C# 代码:

private void btnIngs3FromDishId_Click(object sender, EventArgs e) {
    List<Ingredient> someIngs = new List<Ingredient>();

    Purple_DataClasses1DataContext dbContextCreateMenu = 
        new Purple_DataClasses1DataContext(DataHandler.theConnectionString);
    foreach (var row in dbContextCreateMenu.ingredientNames_givenDishId(10))
            MessageBox.Show(row.ToString());

我也试过:

     var thing = dbContextCreateMenu.ingredientNames_givenDishId(10);
     var anotherThing = thing.AsEnumerable();
        foreach (var subthing in anotherThing)

当我设置断点并将鼠标悬停在 "anotherThing" 上时,最后一个示例实际上显示了 3 个字符串值:

我可以用鼠标向下钻取并查看一次字符串值,然后我会 获得有关后续尝试的通知:{"The query results cannot be enumerated more than once."}

如有任何帮助,我们将不胜感激。谢谢!

@Enigmativity:这很有帮助,而且实施起来非常简单。这是我最终得到的结果,效果很好:

var thing= dbContextCreateMenu.ingredientNames_givenDishId(10);
var anotherThing = thing.ToList();
MessageBox.Show(anotherThing.ElementAt(0).ingredientname);

@Sharag & marc_s:这个老方法也能用!!非常感激。其他刚开始使用它的人需要注意的几点:我需要这一行:

cmd.CommandType = CommandType.StoredProcedure; 

我还需要在此行中将 @dishid 显式设置为 int,否则编译器会将其视为对象:

cmd.Parameters.AddWithValue("@dishid", Convert.ToInt32(aValue));

我不是 LINQ 方面的专家,但如果您想要始终有效的旧方法,请看这里:

List<String> lt = new List<string>();    
     try{

         if (con.State == System.Data.ConnectionState.Closed)
              con.Open();
               cmd.CommandText = qr;\the query 
                SqlDataAdapter adp = new SqlDataAdapter(cmd);
                DataTable dt = new DataTable();
                adp.Fill(dt);
             for(int i=0;i<dt.Rows.Count;i++)
               {lt.Add(dt.Rows[i][0].toString());}
            }
            catch (SqlException exc)
            { MessageBox.Show(exc.Message);  }

在 C# 端,您可以使用 reader、数据表、适配器进行访问。

数据 reader 的示例代码如下所示

SqlConnection connection = new SqlConnection(ConnectionString);

command = new SqlCommand("TestProcedure", connection);
command.CommandType = System.Data.CommandType.StoredProcedure;
connection.Open();

reader = command.ExecuteReader();

List<Test> TestList = new List<Test>();

Test test;

while (reader.Read())
{
    test = new Test();
    test.ID = int.Parse(reader["ID"].ToString());
    test.Name = reader["Name"].ToString();

    TestList.Add(test);
}

最简单的做法是将以下代码中的 .AsEnumerable() 替换为 .ToArray()

 var thing = dbContextCreateMenu.ingredientNames_givenDishId(10);
 var anotherThing = thing.AsEnumerable();
    foreach (var subthing in anotherThing)

成功:

 var thing = dbContextCreateMenu.ingredientNames_givenDishId(10);
 var anotherThing = thing.ToArray();
    foreach (var subthing in anotherThing)

.AsEnumerable() 的问题在于它是一个相当弱的运算符,除了执行转换操作外什么都不做。

这是"System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089":

的反编译源
[__DynamicallyInvokable]
public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source)
{
  return source;
}

它实际上并没有做任何事情来强制执行您的查询。

调用.ToArray()确实会强制执行。

另一种方法是调用 .ToList()。我不提倡这样做,除非您知道要更改列表的成员。每个的性能几乎相同。 .ToArray().ToList() 都将元素添加到最初以 4 个元素开始的数组,然后每次达到当前容量时将容量加倍。但是,调用 .ToArray() 将提高内存效率,因为它在返回数组之前所做的最后一件事是截断缓冲区。因此,包含 1,025 个项目的 List<T> 将在内部包含 2,048 个成员,但是包含 1,025 个元素的 T[] 将仅包含 1,025 个项目 - 用于构造 2,048 个成员的缓冲区可立即用于垃圾回收。