无法使用BeginTextImport / TEXT COPY

时间:2017-02-08 09:05:14

标签: .net postgresql npgsql

我在.Net核心控制台应用程序中使用NPGSql驱动程序(版本3.2.0)。因为我必须插入大量的行,所以我想使用COPY方法,但我总是在postgresql日志文件中得到这些错误:

STATEMENT:  COPY events FROM STDIN WITH DELIMITER AS '  ' NULL AS ''
ERROR:  COPY from stdin failed: 
CONTEXT:  COPY events, line 52

行号似乎经常是1,但似乎是随机的(我得到89,52等),而我只有26列。我不确定这个行号是如何由PGSQL计算的。

另一个问题是,当我尝试/捕获整个代码块时,npgsql不会抛出异常,并且我的foreach循环继续进行我导入的数百万行。我还尝试写入单个StringBuilder并进行单个Write()操作,但结果大致相同:PGSQL中没有导入任何一行,而且我得到的日志与上面相同。

下面是代码的简化版本(我实际上只插入了26列,只有字符串,bool,datetime和int)

pgWriter = pgCnx.BeginTextImport("COPY events FROM STDIN WITH DELIMITER AS '\t' NULL AS ''");

foreach (MyObject o in myArray)
{
   pgWriter.Write("{0}\t", o.b ? "TRUE" : "FALSE");
   pgWriter.Write("{0}\t", o.dt.ToUniversalTime());

   // last column is a string 
   if (o.filepath == null)
   {
       pgWriter.Write("");   // for null values I leave an empty character
   }
   else
   {
      // Escape string before writing it
      string tmp = o.filepath.Replace("\\", "\\\\");
      pgWriter.Write("{0}", tmp);
   }

   // Ends our row
   pgWriter.Write("\n");
}

PS:我确实检查了标签,看起来字符串没有问题。令我恼火的是NPGsql没有捕获任何异常,而PGSQL显然对发送的内容不满意,有没有办法从C#代码中捕获这些问题?

另一个问题:COPY和行查询可用时是否存在延迟?事实上,在我的循环插入行的10s后,我没有看到SELECT查询的任何行,也许有一个我应该调用的flush方法或类似的东西?

非常感谢,

1 个答案:

答案 0 :(得分:0)

首先,在文本模式下执行COPY(BeginTextImport)时,Npgsql不会查看您的输入或以任何方式与其进行交互 - 它只是将其传递给PostgreSQL。如果它有任何错误,PostgreSQL将是抛出错误的那个(正如你所看到的)。 Npgsql没有业务解析您的输入并在此方案中抛出任何异常。

其次,正如注释中所指出的那样,整个COPY操作被认为是一个事务,因此任何行的任何错误都将导致整个操作被回滚,并且不会提交任何行。

第三,为什么不简单地使用二进制COPY(see the docs),而不是以文本格式格式化数据并且不必担心转义和其他与文本相关的问题?在二进制COPY中,你告诉Npgsql导入字符串,整数等,它负责以PostgreSQL二进制格式编码这些值。除了二进制比文本更快,它允许您避免所有格式化/转义相关的问题。

基本上,使用文本COPY的唯一原因是,如果您已经有正确格式化的数据文件,并且可以按原样或多或少地导入PostgreSQL(例如,由某个程序生成)。如果您的导入程序知道这些值,那么最好做二进制文件。