批量 C# 数据表到 postgresql 表

Za7*_*7pi 4 c# postgresql datatable bulkinsert sqlbulkcopy

我有一个包含数千条记录的数据表。我有一个具有相同数据表字段的 postgres 表。我想每天截断这个表并再次填充数据表的数据。我见过 sql 批量复制,但它在 postgres 上不可用。那么,哪一种是最有效的方法呢?

  • 每条记录插入一个
  • 多次插入:插入表值(1,1),(1,2),(1,3),(2,1);
  • 从数据表中选择并使用 linq 插入 postgres?不知道...

谢谢。

Ham*_*one 6

PostgreSQL 确实有一个大容量副本(它实际上被称为copy),并且它有一个很好的 .NET 包装器。如果你正在加载,你想使用NpgsqlCopyIn,如果你正在提取数据,你可以使用NpgsqlCopyOut.

你的问题在细节上有点含糊——我不知道你的数据表中的字段或你的实际数据库的任何信息,所以把它作为一个关于如何使用 C#/PostgreSQL 将数据批量插入到表中的简短示例:

    NpgsqlCopyIn copy = new NpgsqlCopyIn("copy table1 from STDIN WITH NULL AS '' CSV;",
        conn);
    copy.Start();

    NpgsqlCopySerializer cs = new NpgsqlCopySerializer(conn);
    cs.Delimiter = ",";

    foreach (var record in RecordList)
    {
        cs.AddString(record.UserId);
        cs.AddInt32(record.Age);
        cs.AddDateTime(record.HireDate);
        cs.EndRow();
    }

    cs.Close();
    copy.End();
Run Code Online (Sandbox Code Playgroud)

-- 编辑 8/27/2019 --

Npgsql 的构造已经完全改变。下面是上面相同示例的样板,使用二进制导入(文本也可用):

using (var writer = conn.BeginBinaryImport(
    "copy user_data.part_list from STDIN (FORMAT BINARY)"))
{
    foreach (var record in RecordList)
    {
        writer.StartRow();
        writer.Write(record.UserId);
        writer.Write(record.Age, NpgsqlTypes.NpgsqlDbType.Integer);
        writer.Write(record.HireDate, NpgsqlTypes.NpgsqlDbType.Date);
    }

    writer.Complete();
}
Run Code Online (Sandbox Code Playgroud)


Mic*_*rek 5

也许您可以检查我的其他答案,其中我描述了我为这个问题创建的一个小助手,使使用另一个助手非常容易: /sf/answers/3224431941/

编辑:我最近遇到了类似的问题,但我们使用的是 Postgresql。我想使用有效的批量插入,但事实证明这非常困难。我还没有找到任何合适的免费库来在此数据库上执行此操作。我只找到了这个助手: https: //bytefish.de/blog/postgresql_bulk_insert/ ,它也在 Nuget 上。我编写了一个小型映射器,它以实体框架的方式自动映射属性:

public static PostgreSQLCopyHelper<T> CreateHelper<T>(string schemaName, string tableName)
        {
            var helper = new PostgreSQLCopyHelper<T>(schemaName, "\"" + tableName + "\"");
            var properties = typeof(T).GetProperties();
            foreach(var prop in properties)
            {
                var type = prop.PropertyType;
                if (Attribute.IsDefined(prop, typeof(KeyAttribute)))
                    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;
        }
Run Code Online (Sandbox Code Playgroud)

我按以下方式使用它(我的实体名为 Undertake):

var undertakingHelper = BulkMapper.CreateHelper<Model.Undertaking>("dbo", nameof(Model.Undertaking));
undertakingHelper.SaveAll(transaction.UnderlyingTransaction.Connection as Npgsql.NpgsqlConnection, undertakingsToAdd));
Run Code Online (Sandbox Code Playgroud)

我展示了一个事务示例,但也可以通过从上下文检索的正常连接来完成。enterpriseToAdd 是可枚举的普通实体记录,我想将其批量插入到数据库中。

经过几个小时的研究和尝试后,我得到了这个解决方案,正如您所期望的那样,速度更快,并且最终易于使用且免费!我真的建议你使用这个解决方案,不仅是因为上面提到的原因,而且因为它是唯一一个我对 Postgresql 本身没有问题的解决方案,许多其他解决方案可以完美地工作,例如与 SqlServer 一起使用。


Jon*_*nan 1

有一些选项可以批量插入到 PostgreSQL 中。

例如,在我的库中,我使用SQL Copy

COPY TableName (Column1, Column2, Column3) FROM STDIN BINARY
Run Code Online (Sandbox Code Playgroud)

免责声明:我是Bulk-Operations.NET项目的所有者

该库使执行任何类型的批量操作变得非常容易:

  • 批量插入
  • 批量更新
  • 批量删除
  • 批量合并

在包括 PostgreSQL 在内的多个数据库提供商中

// Easy to use
var bulk = new BulkOperation(connection);
bulk.BulkInsert(dt);
bulk.BulkUpdate(dt);
bulk.BulkDelete(dt);
bulk.BulkMerge(dt);
Run Code Online (Sandbox Code Playgroud)