Эффективный способ преобразования IEnumerable в DataTableC#

Место общения программистов C#
Ответить
Anonymous
 Эффективный способ преобразования IEnumerable в DataTable

Сообщение Anonymous »

Прежде чем это будет помечено как дубликат, я видел много ответов, подобных этому.
Преобразуйте IEnumerable в DataTable и пытался сделать что-то подобное, создавая метод расширения. Я задаю свой вопрос, поскольку проблема, с которой я столкнулся, может заключаться где-то еще.
По сути, у меня довольно большой IEnumerable (около 16–17 миллионов элементов) до этого момента у меня не было никаких проблем с этим, пока я не попробовал преобразовать это в DataTable, используя метод расширения:

Код: Выделить всё

/// 
/// Converts IEnumerable to datatable. Mainly for use when using SQLBulkCopy/>
/// 
/// 
/// 

/// Custom order for columns allows me to make sure that the order of columns will always be the same. Am open for suggestions for better ways to do this
/// 
public static DataTable ToDataTable(this IEnumerable collection, List customColumnOrder)
{
DataTable dt = new DataTable();
var type = collection.First().GetType();

foreach (var column in customColumnOrder)
{
dt.Columns.Add(column.Item1, Nullable.GetUnderlyingType(type.GetProperty(column.Item1).PropertyType) ?? type.GetProperty(column.Item1).PropertyType);
}

// Populate the table
foreach (T item in collection)
{
DataRow dr = dt.NewRow();
dr.BeginEdit();

foreach (var column in customColumnOrder)
{
dr[column.Item1] = type.GetProperty(column.Item1).GetValue(item) ?? DBNull.Value;
}

dr.EndEdit();
dt.Rows.Add(dr);
}

return dt;
}
Это отлично работает для небольших таблиц, содержащих около 100 000 элементов, но начинает вызывать затруднения, когда число элементов достигает миллионов. Я просто продолжаю получать тайм-ауты. Есть ли более эффективный/в целом лучший способ преобразования IEnumerable в DataTable?
Я конвертирую в DataTable поэтому я могу использовать SqlBulkCopy для передачи данных в базу данных.
EDIT: отсюда передаются данные

Код: Выделить всё

    /// 
/// SqlBulkCopy for saving large amounts of data
/// 
/// 
/// 

/// Custom manager to use alongside the model
/// Connection string to DB
public void BatchSave(IEnumerable dataToSave, IData modelManager, string conn)
{
var model = dataToSave.First();

using (SqlConnection sqlconn= new SqlConnection(conn))
{
sqlconn.Open();

using (SqlCommand cmd = new SqlCommand(GetCreateScript(modelManager, model), sqlconn))
{
//Create temp table to do initial insert into
cmd.ExecuteNonQuery();

SqlBulkCopy copy = new SqlBulkCopy(cmd.Connection);

copy.DestinationTableName = "#tempTableForImport";

// Convert data to DataTable
DataTable dt = dataToSave.ToDataTable(modelManager.GetDataColumnsOrder());

// Copy to temp table
copy.WriteToServer(dt);
}

using (SqlCommand cmd = new SqlCommand(modelManager.GetInsertSproc(), sqlconn) { CommandType=CommandType.StoredProcedure })
{
// Clean up data and move to final table
cmd.ExecuteNonQuery();
}

sqlconn.Close();
}
}
РЕДАКТИРОВАНИЕ №1: недавно измененный код с использованием сделанного предложения, теперь он использует Fastmember:

Код: Выделить всё

public void BatchSave(IEnumerable dataToSave, IData modelManager, string conn)
{
var model = dataToSave.First();

using (SqlConnection sqlconn = new SqlConnection(conn))
{
sqlconn.Open();

using (var bcp = new SqlBulkCopy(sqlconn))
{
using (var reader = ObjectReader.Create(dataToSave, modelManager.GetDataColumnsOrder().Select(s => s.Item1).ToArray() /*modelManager.GetDataColumnsOrder().Select(obj=>obj.Item1).ToString()*/))
{
using (SqlCommand cmd = new SqlCommand(GetCreateScript(modelManager, model), sqlconn))
{
cmd.ExecuteNonQuery();
bcp.DestinationTableName = "#tempTableForImport";
bcp.WriteToServer(reader);
}

using (SqlCommand cmd = new SqlCommand(modelManager.GetInsertSproc(), sqlconn) { CommandType = CommandType.StoredProcedure })
{
cmd.ExecuteNonQuery();
}
}
}

sqlconn.Close();
}
}
Это ускорило процесс, однако я все еще получаю сообщение «Тайм-аут истек» в этой строке bcp.WriteToServer(reader);.
Спасибо всем за помощь, прошло примерно 30 секунд, есть еще идеи по этому поводу? Может быть, как-нибудь увеличить время до тайм-аута?

Подробнее здесь: https://stackoverflow.com/questions/329 ... -datatable
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»