Member 14169626 Ответов: 3

Как я могу увеличить производительность datatable?


Я использую datatable, и это занимает слишком много времени, чтобы добавить datatable. Как я могу отредактировать datatable, чтобы он не работал медленно, или что я могу использовать вместо datatable?

Как я могу редактировать этот код, работающий очень медленно?

Что я уже пробовал:

public System.Data.DataTable Excels()
{
var employeeInf=myentities.Employee.Select(x=>new {
   ID=x.ID,
   Name=x.Name,
   Surname=x.Surname,
   Branch=x.Branch
}).ToList();

var dataTable=new System.Data.DataTable();
dataTable.Columns.Add("ID");
dataTable.Columns.Add("Name");
dataTable.Columns.Add("Surname");
dataTable.Columns.Add("Branch");

int i=1;

foreach(var t in employeeInf9
{
   var newRow=dataTable.NewRow();
   newRow[ID]=t.ID;
   newRow[ID]=t.Name;
   newRow[ID]=t.Surname;
   newRow[ID]=t.Branch;

  dataTable.Rows.Add(newRow);  i++;

}

3 Ответов

Рейтинг:
2

Gerry Schmitz

Похоже, вы обновляете один и тот же столбец в цикле for. Без "подсчета записей" никто не может сказать, что такое "медленно". И "Толист" здесь излишен. Вы можете попробовать указать "нет отслеживания".


Рейтинг:
1

Richard Deeming

Вот решение для Entity Framework 6, собранное из нескольких постов StackOverflow:
c# - возврат datatable с помощью entity framework - переполнение стека[^] - не работает с параметризованными запросами;
Как я могу получить параметры запроса Entity Framework? - переполнение стека[^] - показывает, как получить доступ к параметрам запроса;

using System;
using System.Data;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Core.EntityClient;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;

namespace EntityFramework
{
    public static class DbContextExtensions
    {
        private static class ReflectionCache<T>
        {
            public static readonly PropertyInfo InternalQuery = typeof(DbQuery<T>).GetProperty("InternalQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        }
        
        public static ObjectQuery<T> GetObjectQuery<T>(this IQueryable<T> source)
        {
            if (source is null) throw new ArgumentNullException(nameof(source));
            if (!(source is DbQuery<T> query)) throw new NotSupportedException();
            
            var internalQuery = ReflectionCache<T>.InternalQuery.GetValue(query, null);
            var objectQueryProperty = internalQuery.GetType().GetProperty("ObjectQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            return (ObjectQuery<T>)objectQueryProperty.GetValue(internalQuery, null);
        }
        
        private static DbCommand ToDbCommand<T>(IQueryable<T> source, out DbProviderFactory dbFactory)
        {
            if (source is null) throw new ArgumentNullException(nameof(source));
            
            var objectQuery = source.GetObjectQuery();
            
            var connection = objectQuery.Context.Connection;
            if (connection is EntityConnection ec) connection = ec.StoreConnection;
            
            dbFactory = DbProviderFactories.GetFactory(connection);
            
            var command = dbFactory.CreateCommand();
            command.Connection = connection;
            command.CommandType = CommandType.Text;
            command.CommandText = objectQuery.ToTraceString();
            
            foreach (var parameter in objectQuery.Parameters)
            {
                var dbParameter = command.CreateParameter();
                dbParameter.ParameterName = parameter.Name;
                dbParameter.Value = parameter.Value;
                command.Parameters.Add(dbParameter);
            }
            
            return command;
        }
        
        public static DbCommand ToDbCommand<T>(this IQueryable<T> source)
        {
            return ToDbCommand(source, out _);
        }
        
        public static DataTable ToDataTable<T>(this IQueryable<T> source)
        {
            if (source is null) throw new ArgumentNullException(nameof(source));
            
            using (var command = ToDbCommand(source, out var dbFactory))
            using (var adapter = dbFactory.CreateDataAdapter())
            {
                adapter.SelectCommand = command;
                
                var dt = new DataTable();
                adapter.Fill(dt);
                return dt;
            }
        }
    }
}
С этим вспомогательным классом на месте ваш код становится:
public DataTable Excels()
{
    var employeeInf = myentities.Employee.Select(x => new
    {
        x.ID,
        x.Name,
        x.Surname,
        x.Branch
    }); // NB: No "ToList" call here.
    
    return employeeInf.ToDataTable();
}


Maciej Los

Ницца. Я должен добавить этот ответ в закладки ;)

Рейтинг:
0

Maciej Los

Я бы посоветовал использовать DataTableExtensions.Метод CopyToDataTable (System.Data) | Microsoft Docs[^] с объект DataTable.Метод LoadDataRow (System.Data) | Microsoft Docs[^]
Видеть:

using System.Data;

public DataTable EmployeesDT
{
    DataTable dt =new DataTable();
    dt.Columns.Add("ID");
    dt.Columns.Add("Name");
    dt.Columns.Add("Surname");
    dt.Columns.Add("Branch");


    dt = employeeInf=myentities.Employee
        .Select(x=> dt.LoadDataRow(new object[]{x.ID, x.Name, x.Surname, x.Branch}, false))
        .CopyToDataTable();
    //done!

    return dt;
}


Richard Deeming

Меня это не убедило. :)

LoadDataRow создает новый DataRow и добавляет его к dt.

CopyToDataTable затем создает новый DataTable например, клонирует каждую строку, возвращаемую Select, и добавляет клонированную строку к новой DataTable пример.

Затем вы храните новое DataTable в dt переменная, выбрасывающая старый экземпляр.

Это эффективно загружает данные дважды и временно использует вдвое больше памяти.

Maciej Los

Что ж...
Вы не можете загрузить данные в datatable без предварительного создания datatable. Ни то, ни другое без использования метода CopyToDataTable ().
;)

Richard Deeming

Но вам не нужно загружать его дважды. :)

DataTable dt =new DataTable();
dt.Columns.Add("ID");
dt.Columns.Add("Name");
dt.Columns.Add("Surname");
dt.Columns.Add("Branch");

foreach (var item in myentities.Employee.Select(x => new { x.ID, x.Name, x.Surname, x.Branch }))
{
    dt.LoadDataRow(new object[] { item.ID, item.Name, item.Surname, item.Branch }, false);
}

return dt;

Maciej Los

ОК. Я понял!
- Спасибо, Ричард.