【问题标题】:C# return multiple columns and rows from SqlDataReaderC# 从 SqlDataReader 返回多列和多行
【发布时间】:2020-06-12 20:48:28
【问题描述】:

我有一个场景来查询数据库的两列并将所有行返回到不同的方法以进行进一步处理。我不确定我下面的方法是否是最好的。您能否分享任何更好的技术来实现这一点。 以下代码适用于从 SQL 返回的单行。

public (Int32 SiteID, string SiteName) QueryDB(string ConnStr)
{
    Int32 SiteID = 0;
    string SiteName = "";
    using (SqlConnection con = new SqlConnection(ConnStr))
        {
            SqlCommand cmd = new SqlCommand("spGetSiteDetails", con);
            con.Open();
            SqlDataReader reader = cmd.ExecuteReader();
            while (reader.Read())
            {
                SiteID = Convert.ToInt32(reader[0]);
                SiteName = reader[1].ToString();
            }
        }
    return (SiteID, SiteName);
}

为了解决多行结果,我使用了在列表中连接的字符串。我相信必须有更好的方法来做到这一点,因为我不得不拆分列表中的字符串以使用这些值。

public List<string> QueryDB(string ConnStr)
{
    List<string> SiteDetails = new List<string>();
    using (SqlConnection con = new SqlConnection(ConnStr))
    {
        SqlCommand cmd = new SqlCommand("spGetSiteDetails", con);
        con.Open();
        SqlDataReader reader = cmd.ExecuteReader();
        while (reader.Read())
        {
            SiteDetails.Add(reader[0] + "|" + reader[1]);
        }
    }
    return SiteDetails;
}

【问题讨论】:

  • 所有 ADO.NET 教程都展示了更好的方法。对于初学者,您可以将所有数据加载到 DataTable 中。或者您可以创建强类型对象并将它们的属性设置为列值。或者,您可以创建一个 List&lt;object&gt; 并向其添加列值,而不是附加字符串。使用 ORM 将行自动转换为对象,或者使用像 Dapper 这样的 microORM 对单行执行相同的操作。
  • 如果 reader[0]reader[1] 是唯一的,您可以将其存储为字典
  • 或者你可以使用reader.GetValues()在一次操作中用所有值填充数组
  • 是否有任何理由不使用具有属性SiteId and SiteName 的类而不是两个单独的变量?

标签: c# .net .net-core


【解决方案1】:

您可以返回List&lt;(int SiteID, string SiteName)&gt;

var list = new List<(int, string)>();
while (reader.Read())
{
    var siteID = Convert.ToInt32(reader[0]);
    var siteName = reader[1].ToString();
    list.Add((siteID, siteName));
}
return list;

但是,我个人建议不要在公共 API 中返回值元组,而是返回您自己的自定义类型 - 即 List&lt;SiteInfo&gt; 用于 class SiteInforeadonly struct SiteInfo em>具有 int SiteIDstring SiteName 作为属性;即

public sealed class SiteInfo
{
    public int SiteID {get;set;}
    public string SiteID {get;set;}
}

var list = new List<SiteInfo>();
while (reader.Read())
{
    var siteID = Convert.ToInt32(reader[0]);
    var siteName = reader[1].ToString();
    list.Add(new SiteInfo { SiteID = siteID, SiteName = siteName });
}
return list;

无论哪种方式:Dapper 都可以帮到你!

public List<(int SiteID, string SiteName)> QueryDB(string ConnStr)
{
    using (SqlConnection con = new SqlConnection(ConnStr))
    {
        return con.Query<(int,string)>("spGetSiteDetails",
              commandType: CommandType.StoredProcedure).AsList();
}

public List<SiteInfo> QueryDB(string ConnStr)
{
    using (SqlConnection con = new SqlConnection(ConnStr))
    {
        return con.Query<SiteInfo>("spGetSiteDetails",
              commandType: CommandType.StoredProcedure).AsList();
}

【讨论】:

    【解决方案2】:

    要返回一个集合,你可以这样写:

    public IEnumerable<(Int32 SiteID, string SiteName)> QueryDB(string ConnStr)
    {
        using (SqlConnection con = new SqlConnection(ConnStr))
        {
                SqlCommand cmd = new SqlCommand("spGetSiteDetails", con);
                con.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    yield return (Convert.ToInt32(reader[0]), reader[1].ToString());
                }
        }
    }
    

    【讨论】:

      【解决方案3】:

      我找到了直接解决问题的DataTable

      dataTable.Load(reader);
      

      【讨论】:

      • Noooooooo.....DataTable 几乎不是解决您问题的正确方法,除非您正在编写临时查询 DSL 或报告 UI。对于应用程序逻辑 - 形状可预测的东西 - 从字面上看,其他任何东西 是可取的。 DataTable 主要是为从 COM ADO RecordSet 迁移到 VB6 的人们搭建的桥梁!!!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多