Skip to main content
 首页 » 编程设计

c#之我可以使用什么强类型数据结构来保存具有不同形状的多个 RecordSet 的集合

2024年02月05日30yxwkf

应我最初问题的回复者的要求 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 列表。希望这能更好地澄清我原来的问题。

请您参考如下方法:

在这种情况下,我认为最好让事情保持简单。

  1. 您有一个返回 3 个结果集的存储过程,因此创建一个包含这 3 个结果集的模型。
  2. 填写您的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")使我们能够获取字段的类型值