Самый быстрый способ преобразования данных в общий список

StackOverflow https://stackoverflow.com/questions/441023

Вопрос

У меня есть метод выбора уровня данных, который возвращает данные. Он вызывается из метода бизнес-уровня, который затем должен возвращать строго типизированный универсальный список List.

То, что я хочу сделать, очень похоже (но не совпадает с) на этот вопрос:
Как преобразовать DataTable в общий список?

Отличительной особенностью является то, что я хочу, чтобы список содержал строго типизированные объекты, а не датарные (также, у меня пока нет доступного linq).

Я беспокоюсь о производительности. Метод бизнес-уровня, в свою очередь, будет вызываться из уровня представления, а результаты будут повторяться для отображения пользователю. Кажется очень расточительным добавление дополнительной итерации на бизнес-уровне, только сделайте это снова сразу для презентации, поэтому я хочу, чтобы это было как можно быстрее.

Это обычная задача, поэтому я действительно ищу хороший шаблон, который можно повторять снова и снова.

Это было полезно?

Решение

Вы заранее знаете структуру 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]));
}

(проблемы, описанные выше, могут привести к правильному подходу ...)

Другие советы

Проблема с примером выше в том, что он ужасно медленный. У меня есть DataTable с 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 секунды!

Вам в любом случае нужно будет перебирать datarows и преобразовывать их в ваши объекты, но вы могли бы написать собственную коллекцию с помощью конструктора, который принимает коллекцию datarow и конвертирует каждый элемент в тип вашего объекта по запросу вместо всего сразу.

Допустим, вы определили свою собственную коллекцию, которая реализует IList<T>. Тогда он может иметь два внутренних поля - ссылку на коллекцию датаров и List<T>. <=> будет инициализирован по длине коллекции датаров, но с нулевыми значениями.

Теперь в индексаторе вы можете проверить, содержит ли <=> значение по этому индексу, и если нет, вы можете создать объект, используя любые полезные средства, и сохранить его там, прежде чем возвращать.

Это откладывает создание ваших объектов до тех пор, пока они не будут запрошены, а вы создадите только те объекты, которые были запрошены.

Вашим объектам, вероятно, понадобится конструктор, принимающий DataRow, или вам понадобится какая-то фабрика для их создания, но это уже другая тема.

Просто для того, чтобы предоставить пользователю удобство ответа на вопрос Марка в простом консольном приложении:

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; 

    }
}
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();
scroll top