将数据表转换为通用列表的最快方法

发布于 2024-07-11 22:14:43 字数 430 浏览 8 评论 0原文

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

我想做的与这个问题非常相似(但不相同):
如何将 DataTable 转换为通用列表?< /a>

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

我担心的是表现。 业务层方法将从表示层调用,并且结果将被迭代以显示给用户。 在业务层添加额外的迭代似乎非常浪费,只有在演示时才立即再次执行,所以我希望这尽可能快。

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

I have a data tier select method that returns a datatable. It's called from a business tier method that should then return a strongly typed generic List.

What I want to do is very similar (but not the same as) this question:
How do you convert a DataTable into a generic list?

What's different is that I want the list to contain strongly-typed objects rather than datarows (also, I don't have linq avaiable here yet).

I'm concerned about performance. The business tier method will in turn be called from the presentation tier, and the results will be iterated for display to the user. It seems very wasteful to add an extra iteration at the business tier, only do it again right away for the presentation, so I want this to be as quick as possible.

This is a common task, so I'm really looking for a good pattern that can be repeated over and over.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

陌上青苔 2024-07-18 22:14:43

上面示例的问题是速度非常慢。 我有一个大约有 400 行的数据表,这个转换需要 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 秒!

The problem with the sample above is that it is terribly slow. I have a DataTable with about 400 rows and this conversion takes a good 5 or 6 seconds!

It does seem like a pretty common task, so I'm surprised to not see someone here with a more performant solution.

* Update!! *
Just for kicks, I thought I would try converting using LINQ instead of iterating through the DataTable and adding to my List. The following is what I did:

   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();

The first method (iterating through each row) took 5.3 seconds and the method using LINQ took 1.8 seconds!

烟若柳尘 2024-07-18 22:14:43

您是否提前知道DataTable 的结构和类型化对象? 您可以使用委托来进行映射。 如果您不知道(即您所知道的只是Type 和属性),则有多种方法可以加速动态成员访问(例如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]));
}

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

Do you know the structure of the DataTable and the typed object ahead of time? You could use a delegate to do the mapping. If you don't (i.e. all you know is a Type and properties) there are ways of accelerating dynamic member access (such as HyperDescriptor).

Either way, consider an iterator block; that way you don't have to buffer the objects an entire second time; of course, if you are only dealing with smallish rowcounts this isn't an issue.

Can you clarify any of those points? I can add a lot more detail...

At the simplest, what is wrong with:

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]));
}

(the problems in the above might steer the right approach...)

游魂 2024-07-18 22:14:43

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

为了让我的答案正确工作,您的列表属性的名称需要与数据库表列(字段)或数据表列名称相同。

解决方案:

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 中的数据表中获取了列表。

记住:类属性中的名称和
数据表/数据库应该相同

I know this answer is very late but i spent an hour and above to prepare this code because i needed this first then i thought some one in search of a solution for this question may get use of this..

Inorder for my answer to work correctly, you need to have same names for your list properties as in the DataBase table-columns(fields) or the DataTable column names.

Solution:

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;
        }

How to use ?

Lets say you have a values populated datatable named dtPersons

DataTable dtPersons; //populate this datatable

Then lets say you have a class with the following properties.

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

Now pack and put the method in your model.
call the method as below.

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

That's it now you got your list from the datatable in listPersons.

Remember: Both the names in the class properties and the
DataTable/Database should be the same

疏忽 2024-07-18 22:14:43

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

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

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

这将推迟对象的创建,直到被请求为止,并且您将只创建所请求的对象。

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

You will need to iterate through the datarows and convert them into your objects at some time anyway, but you could write a custom collection with a constructor that takes a collection of datarows and that converts each item into your object type when requested instead of all at once.

Say you define your custom collection that implements IList<T>. It could then have two internal fields - a reference to the collection of datarows and a List<T>. The List<T> would be initialized to the length of the collection of datarows but with null values.

Now in the indexer you could check if the List<T> contains a value at that index and if not you could create the object using whatever means would be useful and store it there before returning it.

This would postpone the creation of your objects until they were requested and you would only create the objects that were requested.

Your objects would probably need a constructor taking a DataRow or you would need some sort of factory to create them, but that is another topic.

你丑哭了我 2024-07-18 22:14:43

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

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; 

    }
}

Just to provide some more user - friendliness to Mark's answer in a simple console app :

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; 

    }
}
丑丑阿 2024-07-18 22:14:43
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();
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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文