В SQL мы делаем что-то вроде этого для объемной вставки в datatable
SqlBulkCopy copy = new SqlBulkCopy(sqlCon);
copy.DestinationTableName = strDestinationTable;
copy.WriteToServer(dtFrom);
Blockquote
но в PostgreSQL, как это сделать
В SQL мы делаем что-то вроде этого для объемной вставки в datatable
SqlBulkCopy copy = new SqlBulkCopy(sqlCon);
copy.DestinationTableName = strDestinationTable;
copy.WriteToServer(dtFrom);
Blockquote
но в PostgreSQL, как это сделать
Вашему проекту необходимо будет ссылаться на следующую сборку: Npgsql
. Если эта ссылка не видна в Visual Studio, то:
GACInstall.exe
CREATE TABLE "OrderHistory"
(
"OrderId" bigint NOT NULL,
"TotalAmount" bigint,
CONSTRAINT "OrderIdPk" PRIMARY KEY ("OrderId")
)
WITH (
OIDS=FALSE
);
ALTER TABLE "OrderHistory"
OWNER TO postgres;
GRANT ALL ON TABLE "OrderHistory" TO postgres;
GRANT ALL ON TABLE "OrderHistory" TO public;
ALTER TABLE "OrderHistory" ALTER COLUMN "OrderId" SET (n_distinct=1);
GRANT SELECT("OrderId"), UPDATE("OrderId"), INSERT("OrderId"), REFERENCES("OrderId") ON "OrderHistory" TO public;
GRANT SELECT("TotalAmount"), UPDATE("TotalAmount"), INSERT("TotalAmount"), REFERENCES("TotalAmount") ON "OrderHistory" TO public;
Обязательно используйте следующие директивы:
using Npgsql;
using NpgsqlTypes;
Введите следующий код в свой метод:
// Make sure that the user has the INSERT privilege for the OrderHistory table.
NpgsqlConnection connection = new NpgsqlConnection("PORT=5432;TIMEOUT=15;POOLING=True;MINPOOLSIZE=1;MAXPOOLSIZE=20;COMMANDTIMEOUT=20;COMPATIBLE=2.2.4.3;DATABASE=test;HOST=127.0.0.1;PASSWORD=test;USER ID=test");
connection.Open();
DataSet dataSet = new DataSet();
NpgsqlDataAdapter dataAdapter = new NpgsqlDataAdapter("select * from OrderHistory where OrderId=-1", connection);
dataAdapter.InsertCommand = new NpgsqlCommand("insert into OrderHistory(OrderId, TotalAmount) " +
" values (:a, :b)", connection);
dataAdapter.InsertCommand.Parameters.Add(new NpgsqlParameter("a", NpgsqlDbType.Bigint));
dataAdapter.InsertCommand.Parameters.Add(new NpgsqlParameter("b", NpgsqlDbType.Bigint));
dataAdapter.InsertCommand.Parameters[0].Direction = ParameterDirection.Input;
dataAdapter.InsertCommand.Parameters[1].Direction = ParameterDirection.Input;
dataAdapter.InsertCommand.Parameters[0].SourceColumn = "OrderId";
dataAdapter.InsertCommand.Parameters[1].SourceColumn = "TotalAmount";
dataAdapter.Fill(dataSet);
DataTable newOrders = dataSet.Tables[0];
DataRow newOrder = newOrders.NewRow();
newOrder["OrderId"] = 20;
newOrder["TotalAmount"] = 20.0;
newOrders.Rows.Add(newOrder);
DataSet ds2 = dataSet.GetChanges();
dataAdapter.Update(ds2);
dataSet.Merge(ds2);
dataSet.AcceptChanges();
connection.Close();
В оригинальной публикации не упоминалось о требованиях к производительности. Было предложено, чтобы решение должно:
DataTable
Если вы вставляете значительные объемы данных, я бы предложил вам взглянуть на ваши параметры производительности. Документация Postgres предполагает, что вы:
COPY
Для получения дополнительной информации об оптимизации вложений Postgres, пожалуйста, взгляните на:
Кроме того, существует множество других факторов, которые могут повлиять на производительность системы. Для ознакомления с высоким уровнем ознакомьтесь с:
COPY
?
Npgsql
и добавить свой собственный BulkCopy()
. Обязательно сначала просмотрите лицензионное соглашение с исходным кодом.Postgres
, которая затем может вставить данные непосредственно в пункт назначения.У меня такая же проблема. Кажется, до сих пор нет "готового к использованию" решения.
Я прочитал этот пост и построил аналогичное решение в то время, которое до сегодняшнего дня находится в эффективном использовании. Он основан на текстовых запросах, которые читают файлы из STDIN. Он использует ADO.NET Postgre Data Provider Npgsql. Вы можете создать большую строку (или временный файл, причину использования памяти) на основе вашего DataTable и использовать его как текстовый запрос с помощью команды COPY. В нашем случае это было намного быстрее, чем научить строки.
Возможно, это не полное решение, но может быть хорошим началом и всем, что я знаю об этом.:)
Я также обнаружил, что пока нет готового к использованию решения. Вероятно, вы можете проверить мой другой ответ, в котором я описываю небольшой помощник, который я создал для этой проблемы, используя простой помощник: fooobar.com/questions/15074/... Я считаю, что в настоящее время это лучшее решение. Я отправил решение из ссылки в случае, если сообщение умерло.
Изменить: Я недавно столкнулся с подобной проблемой, но мы использовали Postgresql. Я хотел использовать эффективный bulkinsert, что оказалось довольно сложным. Я не нашел в этой БД надлежащей бесплатной библиотеки. Я нашел только этого помощника: https://bytefish.de/blog/postgresql_bulk_insert/ который также находится на Nuget. Я написал небольшой картограф, который автоматически сопоставил свойства как Entity Framework:
public static PostgreSQLCopyHelper<T> CreateHelper<T>(string schemaName, string tableName)
{
var helper = new PostgreSQLCopyHelper<T>("dbo", "\"" + tableName + "\"");
var properties = typeof(T).GetProperties();
foreach(var prop in properties)
{
var type = prop.PropertyType;
if (Attribute.IsDefined(prop, typeof(KeyAttribute)) || Attribute.IsDefined(prop, typeof(ForeignKeyAttribute)))
continue;
switch (type)
{
case Type intType when intType == typeof(int) || intType == typeof(int?):
{
helper = helper.MapInteger("\"" + prop.Name + "\"", x => (int?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type stringType when stringType == typeof(string):
{
helper = helper.MapText("\"" + prop.Name + "\"", x => (string)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type dateType when dateType == typeof(DateTime) || dateType == typeof(DateTime?):
{
helper = helper.MapTimeStamp("\"" + prop.Name + "\"", x => (DateTime?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type decimalType when decimalType == typeof(decimal) || decimalType == typeof(decimal?):
{
helper = helper.MapMoney("\"" + prop.Name + "\"", x => (decimal?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type doubleType when doubleType == typeof(double) || doubleType == typeof(double?):
{
helper = helper.MapDouble("\"" + prop.Name + "\"", x => (double?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type floatType when floatType == typeof(float) || floatType == typeof(float?):
{
helper = helper.MapReal("\"" + prop.Name + "\"", x => (float?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type guidType when guidType == typeof(Guid):
{
helper = helper.MapUUID("\"" + prop.Name + "\"", x => (Guid)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
}
}
return helper;
}
Я использую его следующим образом (у меня был объект с именем Undertaking):
var undertakingHelper = BulkMapper.CreateHelper<Model.Undertaking>("dbo", nameof(Model.Undertaking));
undertakingHelper.SaveAll(transaction.UnderlyingTransaction.Connection as Npgsql.NpgsqlConnection, undertakingsToAdd));
Я показал пример с транзакцией, но это также можно сделать с обычным подключением, полученным из контекста. предпринимателиToAdd перечислимы для обычных записей сущностей, которые я хочу загрузить в DB.
Это решение, которое я получил после нескольких часов исследований и попыток, так же, как вы могли ожидать гораздо быстрее и, наконец, легко использовать и бесплатно! Я действительно советую вам использовать это решение не только по причинам, упомянутым выше, но и потому, что это единственный, с которым у меня не было проблем с самим Postgresql, многие другие решения работают безупречно, например, с SqlServer.
Вы действительно хотите использовать DataTable для этого? Если вы можете использовать EF Code First, тогда вы можете использовать код из этой статьи . Идея статьи состоит в том, чтобы использовать Npgsql COPY в качестве базы + извлечения метаданных из самого БД, объединить ее с метаданными из классов моделей и динамически генерировать код для записи данных.
Использование выглядит так:
var uploader = new NpgsqlBulkUploader(context);
var data = GetALotOfData();
uploader.Insert(data);
// OR
uploader.Update(data);