我目前正在编写一个程序,它从 SQL 接收 3 个表,其中包含我正在使用的每个表中的数据,并通过行来创建相应类的对象。
经过一步一步的调试,我可以看到DataSet中的数据确实是正确的,但我似乎无法通过名称访问它。 当我使用索引访问数据集中的表时,它工作得很好,就像这样 -
DataSet ds = new ProgramProcedures().GetTestByUser(UserId);
if (ds.Tables[0].IsHasRows())
{
foreach (DataRow _dr in ds.Tables[0].Rows)
{
TestList.Add(new Test(_dr));
}
}
当我尝试按名称访问它时,它失败并且不输入 if 语句。
DataSet ds = new ProgramProcedures().GetTestByUser(UserId);
if (ds.Tables["Name1"].IsHasRows())
{
foreach (DataRow _dr in ds.Tables["Name1"].Rows)
{
TestList.Add(new Test(_dr));
}
}
在存储过程中,数据来自我包含以下几行 -
@tables nvarchar(max)='' output
set @tables='Name1,Name2,Name3'
调试检查ds变量内容时,数据正确,但表名是“Table, Table1, Table2” 我究竟做错了什么?我想按名称访问表,因为它使代码在对其或过程进行任何更改时更加可靠。
我尝试使用表的索引而不是它们的名称,这非常有效,但我想使用表的名称。
表名称是根据数据集中的表数量自动生成的,因此您的输出参数不会自动映射。我也不知道你在哪里消费它。
我创建了一个示例 DB 和 SP,它运行没有问题:
CREATE PROCEDURE GetTestByUser
-- Add the parameters for the stored procedure here
@UserId int,
@TableNames nvarchar(max) = '' OUTPUT
AS
BEGIN
SET NOCOUNT ON;
set @TableNames ='Table1,Table2'
-- Insert statements for procedure here
SELECT * FROM Table1
SELECT * FROM Table2
END
GO
您需要使用数据才能检索输出参数。因此,要么显式关闭
SqlDataReader
,要么使用像 SqlDataAdapter.Fill
这样的内置方法在最后关闭连接:
using SqlConnection con = new(connectionString);
using SqlCommand command = new("dbo.GetTestByUser", con);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("@UserId", 1);
SqlParameter tableNamesOutParameter = new("@TableNames", SqlDbType.NVarChar, 1000)
{ Direction = ParameterDirection.Output };
command.Parameters.Add(tableNamesOutParameter);
DataSet ds = new();
using SqlDataAdapter da = new(command);
da.Fill(ds);
string[] tableNames = tableNamesOutParameter.Value?.ToString()?.Split(',', StringSplitOptions.TrimEntries) ?? Array.Empty<string>();
for (int i = 0; i < tableNames.Length; i++)
{
ds.Tables[i].TableName = tableNames[i];
}
// now you can access each table by the correct name:
DataTable? table1 = ds.Tables["Name1"];
if (table1?.AsEnumerable().Any() == true)
{
foreach (DataRow _dr in table1.Rows)
{
TestList.Add(new Test(_dr));
}
}