6

我有一个返回数据表的数据层选择方法。它是从一个业务层方法调用的,然后应该返回一个强类型的泛型列表。

我想做的与这个问题非常相似(但不一样):
How do you convert a DataTable into a generic list?

不同的是我希望列表包含强类型对象而不是数据行(另外,我这里还没有可用的 linq)。

我担心性能。业务层方法将依次从表示层调用,结果将被迭代以显示给用户。在业务层添加一个额外的迭代似乎非常浪费,只是为了演示而立即再做一次,所以我希望这尽可能快。

这是一个常见的任务,所以我真的在寻找一个可以一遍又一遍地重复的好模式。

4

6 回答 6

9

上面示例的问题是它非常慢。我有一个大约 400 行的 DataTable,这个转换需要 5 到 6 秒!

这似乎是一项非常常见的任务,所以我很惊讶在这里没有看到有人提供更高性能的解决方案。

* 更新!!* 只是为了好玩,我想我会尝试使用 LINQ 进行转换,而不是遍历 DataTable 并添加到我的列表中。以下是我所做的:

   List<MyObject> returnList = new List<MyObject>();

   MyDataTable dtMyData = new MyTableAdapter().GetMyData();

   returnLists = (from l in dtMyData
                 select new MyObject
                 {
                    Active = l.IsActive,
                    Email = l.Email,
                    //...
                    //About 40 more properties
                    //...
                    ZipCode = l.Zipcode
                  }).ToList();

第一种方法(遍历每一行)耗时 5.3 秒,使用 LINQ 的方法耗时 1.8 秒!

于 2010-05-21T14:43:37.533 回答
7

DataTable提前知道了和类型化对象的结构吗?您可以使用委托来进行映射。如果您不这样做(即您只知道 aType和属性),则有一些方法可以加速动态成员访问(例如HyperDescriptor)。

无论哪种方式,考虑一个迭代器块;这样您就不必第二次缓冲对象;当然,如果您只处理较小的行数,这不是问题。

你能澄清其中的任何一点吗?我可以添加更多细节...

最简单的是,有什么问题:

DataTable table = new DataTable {
    Columns = {
        {"Foo", typeof(int)},
        {"Bar", typeof(string)}
     }
};
for (int i = 0; i < 5000; i++) {
    table.Rows.Add(i, "Row " + i);
}

List<MyType> data = new List<MyType>(table.Rows.Count);
foreach (DataRow row in table.Rows) {
    data.Add(new MyType((int)row[0], (string)row[1]));
}

(上述问题可能会引导正确的方法......)

于 2009-01-13T22:18:24.703 回答
1

我知道这个答案很晚了,但我花了一个多小时来准备这段代码,因为我首先需要这个,然后我认为寻找这个问题的解决方案的人可能会使用这个..

为了使我的答案正常工作,您的列表属性的名称需要与 DataBase 表列(字段)或 DataTable 列名称中的名称相同。

解决方案:

public List<dynamic> GetListFromDT(Type className, DataTable dataTable)
        {
            List<dynamic> list = new List<dynamic>();
            foreach (DataRow row in dataTable.Rows)
            {
                object objClass = Activator.CreateInstance(className);
                Type type = objClass.GetType();
                foreach (DataColumn column in row.Table.Columns)
                {
                    PropertyInfo prop = type.GetProperty(column.ColumnName);
                    prop.SetValue(objClass, row[column.ColumnName], null);   
                }
                list.Add(objClass);
            }
            return list;
        }

如何使用 ?

假设您有一个名为 dtPersons 的填充数据表

DataTable dtPersons; //populate this datatable

然后假设您有一个具有以下属性的类。

public class Persons{
    public string Name {get; set;}
    public int Age {get; set;}
}

现在打包并将方法放入您的模型中。调用方法如下。

List<dynamic> dynamicListReturned = GetListFromDT(typeof(Persons), dataTable);
List<Persons> listPersons = dynamicListReturned.Cast<Persons>().ToList();

就是这样,现在您从listPersons的数据表中获得了您的列表。

请记住:类属性和 DataTable/Database 中的名称应该相同

于 2019-10-29T12:50:32.143 回答
0

无论如何,您将需要遍历数据行并将它们转换为您的对象,但是您可以使用构造函数编写一个自定义集合,该构造函数采用数据行的集合,并在请求时将每个项目转换为您的对象类型,而不是全部一次。

假设您定义了实现IList<T>. 然后它可以有两个内部字段——一个对数据行集合的引用和一个List<T>. 将List<T>被初始化为数据行集合的长度,但具有空值。

现在在索引器中,您可以检查该索引List<T>处是否包含值,如果没有,您可以使用任何有用的方法创建对象并将其存储在那里,然后再返回它。

这将推迟对象的创建,直到它们被请求,并且您只会创建被请求的对象。

您的对象可能需要使用 DataRow 的构造函数,或者您需要某种工厂来创建它们,但这是另一个主题。

于 2009-01-13T22:31:24.243 回答
0

只是为了在一个简单的控制台应用程序中为 Mark 的回答提供更多的用户友好性:

class Program
{
    static void Main(string[] args)
    {
        //define a DataTable obj
        DataTable table = new DataTable
        {
            Columns = {
            {"Foo", typeof(int)},
            {"Bar", typeof(string)}
         }
        };
        //populate it the DataTable 
        for (int i = 0; i < 3; i++)
        {
            table.Rows.Add(i, "Row " + i);
        }

        List<MyType> listWithTypedObjects= new List<MyType>(table.Rows.Count);
        foreach (DataRow row in table.Rows)
        {
            listWithTypedObjects.Add(new MyType((int)row[0], (string)row[1]));
        }

        Console.WriteLine(" PRINTING THE POPULATED LIST ");
        foreach (MyType objMyType in listWithTypedObjects)
        {
            Console.Write(" I have object of the type " + objMyType.ToString() + " => " );
            Console.Write(" with Prop1OfTypeInt " + objMyType.Prop1OfTypeInt.ToString() + " , ");
            Console.WriteLine(" with Prop1OfTypeInt " + objMyType.Prop2OfTypeString.ToString() + "  "); 
        }

        Console.WriteLine(" \n \n \n HIT A KEY TO EXIT THE PROGRAM ");
        Console.ReadKey();
    }
}

class MyType {

    public int Prop1OfTypeInt { get; set; }
    public string Prop2OfTypeString { get; set; } 

    /// <summary>
    /// Note the order of the passed parameters is important !!!
    /// </summary>
    public MyType( int prop1OfTypeInt , string prop2OfTypeString)
    {
        this.Prop1OfTypeInt = prop1OfTypeInt;
        this.Prop2OfTypeString = prop2OfTypeString; 

    }
}
于 2010-01-26T07:36:13.263 回答
-5
public partial class issuereceive_manageroffice_bal
{
    public int issue_id{get;set;}
    public string process{get;set;}
    public DateTime issue_date{get;set;}
    public TimeSpan issue_time{get;set;}
    public string eg_no{get;set;}
    public string lotno{get;set;}
    public string clarity{get;set;}
    public string sieves{get;set;}
    public string shape{get;set;}
    public double issue_carat{get;set;}
    public int issue_pieces{get;set;}
    public int receive_pieces{get;set;}
    public double receive_carat{get;set;}
    public int kp_pieces{get;set;}
    public decimal kp_carat{get;set;}
    public double loss{get;set;}
    public string issue_manager{get;set;}
    public string issue_by{get;set;}
    public string receive_by{get;set;}
    public int status{get;set;}
    public DateTime receive_date{get;set;}
    public string receive_time{get;set;}
    public int factory_id{get;set;}

}


List<issuereceive_manageroffice_bal> issue_receive_list = new List<issuereceive_manageroffice_bal>();
issue_receive_list =
      (from DataRow dr in DataTable.Rows
      select new issuereceive_manageroffice_bal()
           {
               issue_id = 0,
               issue_time = TimeSpan.Parse("0"),
               receive_time = null,
               shape = null,
               process = dr["process"].ToString(),
               issue_date = Convert.ToDateTime(dr["issue_date"]),
               eg_no = dr["eg_no"].ToString(),
               lotno = dr["lotno"].ToString(),
               clarity = dr["clarity"].ToString(),
               sieves = dr["sieves"].ToString(),
               issue_carat = dr["issue_carat"].ToString() != "" ? double.Parse(dr["issue_carat"].ToString()) : 0,
               issue_pieces = dr["issue_pieces"].ToString() != "" ? int.Parse(dr["issue_pieces"].ToString()) : 0,
               receive_carat = dr["receive_carat"].ToString() != "" ? double.Parse(dr["receive_carat"].ToString()) : 0,
               kp_pieces = dr["kp_pieces"].ToString() != "" ? int.Parse(dr["kp_pieces"].ToString()) : 0,
               kp_carat = dr["kp_carat"].ToString() != "" ? decimal.Parse(dr["kp_carat"].ToString()) : 0,
               loss = dr["loss"].ToString() != "" ? double.Parse(dr["loss"].ToString()) : 0,
               issue_manager = dr["lotno"].ToString(),
               issue_by = dr["issue_by"].ToString(),
               receive_by = dr["receive_by"].ToString(),
               status = dr["status"].ToString() != "" ? int.Parse(dr["status"].ToString()) : 0,
               receive_date = Convert.ToDateTime(dr["receive_date"]),
               factory_id = dr["factory_id"].ToString() != "" ? int.Parse(dr["factory_id"].ToString()) : 0,

           }).ToList();
于 2015-04-10T07:42:55.317 回答