应我最初问题的回复者的要求 here , 我被要求改写问题以深入了解实际需求。
我可以使用什么Strongly-Typed 数据结构来保存多个RecordSet 的集合,其中每个RecordSet 将包含可能是与其他 RecordSets 形状不同?
这种需求是由于需要通过 DbDataReader 处理从存储过程返回的数据。 存储过程可能有多个RecordSet,每个RecordSet返回不同的列和列数。
将有 DTO 类来表示相应数据集的每一行。这些在编译时是已知的。我需要的是一个可以保存多个 RecordSet 的数据结构,并且对于每个 RecordSet 保存代表从 返回的行的 DTO记录集。
示例存储过程:
CREATE PROCEDURE [dbo].[MultipleRecordSetStoredProcedure]
@Id INT
, @Name VARCHAR(20)
, @Active BIT
, @Price DECIMAL(10, 4)
, @UniqueIdentifier UNIQUEIDENTIFIER
, @Count TINYINT
AS
BEGIN
/* First Record Set */
SELECT
@Id AS Id
, @Name AS Name
UNION
SELECT
17 AS Id
, 'Bill' AS Name;
/* Second Record Set */
SELECT
@Name AS Name,
@Active as Active
UNION
SELECT
'Bill' AS Name
, CAST(0 AS BIT) AS Active;
/* Third Record Set */
SELECT
@UniqueIdentifier AS UNIQUEIDENTIFIER
, @Count AS Count
UNION
SELECT
NEWID() AS UNIQUEIDENTIFIER
, CAST(10 AS TINYINT) AS Count;
END
示例调用代码:
DbConnection connection = CreateConnection();
CommandBehavior commandBehavior = CommandBehavior.Default;
// Create a command to execute the stored storedProcedure
using (DbCommand command = connection.CreateStoredProcedureCommand(
procedureName,
procedureParameters,
commandTimeout,
transaction))
{
// Populate a DataReder by calling the command
using (DbDataReader reader = command.ExecuteReader(commandBehavior))
{
// Iterate through each result set...
do
{
// Process the result set line by line
while (reader.Read())
{
// Read data into DataStructure
}
} while (reader.NextResult());
}
}
示例 DTO:
internal class MultipleRecordSetStoredProcedureReturnType1
{
public int Id { get; set; }
public string Name { get; set; }
}
internal class MultipleRecordSetStoredProcedureReturnType2
{
public bool Active { get; set; }
public decimal Decimal { get; set; }
}
internal class MultipleRecordSetStoredProcedureReturnType3
{
public Guid UniqueIdentifier { get; set; }
public Byte Count { get; set; }
}
理想情况下,我不需要对象 或动态 列表,而是我的记录集内容的 DTO 列表。希望这能更好地澄清我原来的问题。
请您参考如下方法:
在这种情况下,我认为最好让事情保持简单。
- 您有一个返回 3 个结果集的存储过程,因此创建一个包含这 3 个结果集的模型。
- 填写您的
ResultModel,最好用SqlDataAdapter和DataSet.它使事情变得非常简单,比数据读取器更容易。
ResultModel 的代码:
public class ResultModel
{
public List<Type1> List1 { get; set; }
public List<Type2> List2 { get; set; }
public List<Type3> List3 { get; set; }
}
我想这些是您的类型:
public class Type1
{
public int A { get; set; }
}
public class Type2
{
public int B { get; set; }
public string C { get; set; }
}
public class Type3
{
public int D { get; set; }
public string E { get; set; }
public string F { get; set; }
}
您可以使用 SqlDataAdapter 和 DataSet 填充您的 ResultModel:
public ResultModel GetData()
{
var connection = @"data source=(localdb)\v11.0;initial catalog=TestDB;integrated security=True;MultipleActiveResultSets=True;";
var command = "dbo.Procedure";
var tableAdapter = new System.Data.SqlClient.SqlDataAdapter(command, connection);
tableAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;
var dataSet = new DataSet();
tableAdapter.Fill(dataSet);
var t1 = dataSet.Tables[0].Rows.Cast<DataRow>()
.ToList().Select(row => new Type1
{
A = row.Field<int>("A"),
}).ToList();
var t2 = dataSet.Tables[1].Rows.Cast<DataRow>()
.ToList().Select(row => new Type2
{
B = row.Field<int>("B"),
C = row.Field<string>("C")
}).ToList();
var t3 = dataSet.Tables[1].Rows.Cast<DataRow>()
.ToList().Select(row => new Type3
{
D = row.Field<int>("D"),
E = row.Field<string>("E"),
F = row.Field<string>("F")
}).ToList();
var result = new ResultModel() { List1 = t1, List2 = t2, List3 = t3 };
return result;
}
这里的重点是:
- 我们有一个干净简单的
ResultModel - 使用
SqlDataAdapter和一个DataSet使读取多个结果变得如此容易。 - 使用
Cast<DataRow>()使我们能够使用Linq反对DataTable.Rows - 使用
Field<T>("field")使我们能够获取字段的类型值
