Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用C#和Npgsql快速插入父表和子表_C#_Postgresql_Npgsql - Fatal编程技术网

使用C#和Npgsql快速插入父表和子表

使用C#和Npgsql快速插入父表和子表,c#,postgresql,npgsql,C#,Postgresql,Npgsql,我使用的是C#.NET 4.0(Visual Studio 2010)、PostgreSQL 9.2和Npgsql 2.0.12。我无法升级到Npgsql 3 我需要快速插入父表,然后使用插入中的主键快速插入子表 父表有一个定义为“串行”的列,该列是主键 子表有一个整数列,该列是返回父表的外键 并非每个父记录都有子记录。父级可以有0、1或多个子级 目前,我正在将父对象缓冲到一个列表中。缓冲5000个父线程后,从线程池中生成一个新线程,将记录写入数据库。(将创建一个新列表 用于主线程缓冲下一组父对

我使用的是C#.NET 4.0(Visual Studio 2010)、PostgreSQL 9.2和Npgsql 2.0.12。我无法升级到Npgsql 3

我需要快速插入父表,然后使用插入中的主键快速插入子表

父表有一个定义为“串行”的列,该列是主键

子表有一个整数列,该列是返回父表的外键

并非每个父记录都有子记录。父级可以有0、1或多个子级

目前,我正在将父对象缓冲到一个列表中。缓冲5000个父线程后,从线程池中生成一个新线程,将记录写入数据库。(将创建一个新列表 用于主线程缓冲下一组父对象。) 新线程调用NpgsqlConnection.BeginTransaction(),然后在循环内使用参数调用NpgsqlCommand.ExecuteScalar(),以插入父记录并取回主键。 然后构建父对象的子对象(如果有)并保存到另一个列表。在循环结束时,提交父级事务。但这种方法的速度非常缓慢。插入5000条记录需要3到10秒的时间。当然还有更好的办法

提交父记录后,我使用中描述的BulkCopy(使用NpgsqlCopyIn)插入子记录。这真是太棒了。它在不到半秒钟的时间内插入了数千条子记录

我也很想把那份复印件用在父母的记录上。但是我不知道如何从批量插入中获取主键值

那么,使用C#和Npgsql快速插入父记录和子记录的诀窍是什么呢?答案可能就在某个地方,但显然我没有使用正确的搜索引擎参数


事先非常感谢。

这种情况的答案通常是这样的。简而言之,这意味着,您可以预先分配大量ID,并在插入时指定它们,而不是让数据库在每次插入时生成ID(强制您检索这些ID)。这意味着您要自己在每个父级上设置ID,而不是将其留空(并让PostgreSQL完成)


具体地说,您将从管理父表ID的序列中检索一批ID—有关更多信息,请参阅和。然后,一旦在应用程序中有了ID,就可以批量插入带有这些ID的父级

我会将parents insert脚本写入一个文本文件中的磁盘,然后通过一个常规命令运行它,以在数据库的一次往返中获取所有parents主键。

当您使用
串行
数据类型时,Postgres会自动生成并分配一个序列。这很好,因为您可以出于其他目的劫持该序列,包括这一个

这是我的建议

假设您的对象如下所示:

public Parent
{
    public long Id { get; set; }
    public string Description { get; set; }
    public List<Child> Children { get; set; }
}

public Child
{
    public long Id { get; set; }
    public long ParentId { get; set; }
    public string Description { get; set; }
}
如果那些记录不存在,
Where
子句可能并不重要。。。只是想一想


从这里开始,您的
NpgsqlCopyIn
应该为家长和孩子们带来惊喜。

感谢@Hambone,也感谢所有提供意见的人。这个解决方案非常有效。我对调用ExecuteScalar的速度印象深刻,因为只需执行“选择下一步…”。干杯
NpgsqlCommand cmd = new NpgsqlCommand("select nextval('schema.foo_id_seq')", conn);
foreach (Parent p in parentList.Where(x => x.Id == null && x.Id == 0))
{
    p.Id = Convert.ToInt64(cmd.ExecuteScalar());
    p.Children.ForEach(x => x.ParentId = p.Id);
}