【问题标题】:Can I Fill a List using a DataAdapter C#我可以使用 DataAdapter C# 填充列表吗
【发布时间】:2011-06-22 12:29:45
【问题描述】:

假设我有这段代码(伪代码)

class SomeClass
{
   class Person
   {
      public static string Name { get; set; }
      public static int Age { get; set; }
   }

   List<Person> person = new List<person>;

   public void SelectPerson()
   {
      DataTable dt = new DataTable();

      SqlConnection conn = GetConnection();
      conn.Open();

      SqlDataAdapter da = new SqlDataAdapter("SELECT name, age FROM person", conn);
      da.Fill(dt);
   }
}

我可以根据我的 DataAdapter 的结果填写列表(人)吗? 我该怎么做?或者有什么解决方法吗?谢谢...

【问题讨论】:

  • Pwninstein 提出了一个有趣的观点。为什么人名和年龄是静态的?

标签: c# ado.net


【解决方案1】:

一位用户最近问我一个关于在 .NET 2.0 中将 DataTable 转换为 List 的问题。这是执行此操作的代码:

C#

// Assuming there is a DataTable called dt

List<DataRow> drlist = new List<DataRow>();

foreach (DataRow row in dt.Rows)
{
    drlist.Add((DataRow)row);
}

【讨论】:

    【解决方案2】:

    可能最好的方法不是先读入数据表:

    var dr = new DataReader(....) // Fill in what is needed, can't remember offhand
    while(dr.Next())
    {
        persons.Add(
            new Person() {
                Name = (string) r["Name"], 
                Age = (int) r["Age"] 
            }
        );
    }
    

    警告:您想快速关闭 DataReader/连接,不要进行大量处理。上述代码比使用 DataTable 作为中介更高效。

    但如果您确实想先使用数据表,则可以使用 LINQ:

    var list = dt.AsEnumerable().Select(r => new Person() { 
        Name = (string) r["Name"], 
        Age = (int) r["Age"] }
    ).ToList()
    

    或者只是迭代 dt.Rows 并创建一个新人并将其添加到列表中

    您还应该在connection and reader 周围使用Using() statements

    【讨论】:

    • 虽然 linq 版本不工作...数据表没有dt.Rows.Select
    • 抱歉,使用 dt.AsEnumerable(),我对 dr.Row 集合不是特别熟悉。帖子已修复
    • 这行得通 --> 除了真正处理空值或您无法将“System.DBNull”类型的对象转换为“System.String”类型,但我意识到这不适合您处理答案错误:)
    • DataReader 不是很好的性能解决方案。也许从 DataTable/DataRow 继承一些会更好
    • @Hamid 你能澄清一下这些问题,什么是更高效的解决方案? IIRC 大多数使用 ADO.NET 读取数据的解决方案将使用数据读取器(包括填充数据表)。我唯一能想到的是你不想让数据读取器打开太久,这是通过一个紧密的循环来实现的。在大多数情况下,数据库读取性能并不是什么大问题。
    【解决方案3】:

    除了提供的其他选项外,您还可以使用 yield 将执行推迟到需要时:

    public static IEnumerable<Person> GetPeople()
    {
        using( var conn = GetConnection() )
        {
            conn.Open();
            string sql = "SELECT name, age FROM person";
            var cmd = new SqlCommand( sql, conn );
    
            using( SqlDataReader rdr = cmd.ExecuteReader() )
            {
                if( rdr == null )
                {
                    throw new NullReferenceException( "No People Available." );
                }
                while( rdr.Read() )
                {
                    var person = new Person();
                    person.Name = rdr["name"].ToString();
                    person.Age = Convert.ToInt32 ( rdr["age"] );
    
                    yield return person;
                }           
            }
        }
    }
    

    【讨论】:

    • 这有潜在的危险,因为在调用代码进行迭代时连接处于打开状态。另外,如果调用者没有到达集合的末尾会发生什么?连接是否被释放?
    • 我想大多数代码都有潜在的危险。您的观点已被理解并应予以考虑。这是C# IEnumerator/yield structure with databases的好读物
    【解决方案4】:

    还有 Linq to DataSet 可以用来做一些类似的事情

    var list = (from tr in dt.AsEnumerable()
        select new Person() { 
            Name = tr.Field<string>("Name"), 
            Age = tr.Field<int>("Age") 
        }).ToList();
    

    Robert 击败了我,只是使用了稍微不同的语法。

    【讨论】:

    • 这可能更好,我对 Linq to DataSets 不熟悉,因为我像瘟疫一样避免使用它们。
    • @Robert Wagner:和我一样,但我们时不时地必须使用遗留代码。
    • 确实如此,但幸好我没有 C# 3.0 和数据集的交集
    【解决方案5】:

    首先,您需要将 Name 和 Age 字段设为非静态(因此类的每个实例都将有自己的这些属性值。

    然后你可以这样做:

    foreach(DataRow row in dt.Rows){
        Person p = new Person(){
            Name = Convert.ToString(row["name"]),
            Age = Convert.ToInt32(row["age"])
        }
        person.Add(p);
    }
    

    希望这会有所帮助!

    【讨论】:

      【解决方案6】:

      是的,你可以。遍历dt.Rows 中的项目并手动将它们转换为Person 对象。

      【讨论】:

        猜你喜欢
        • 2011-08-13
        • 2011-11-30
        • 2022-01-02
        • 2012-04-10
        • 2018-07-20
        • 1970-01-01
        • 1970-01-01
        • 2013-04-11
        • 1970-01-01
        相关资源
        最近更新 更多