Search code examples
npgsql

In NpgSql Insert bit datatype using BeginBinaryImport for bulk data insertion


I have been trying to implement bulk insert operation for postgre database using Npgsql version 3.1.2, but I had facing one issue ('insufficient data left in message ') regarding datatype miss match for the column paymentdone(bit(1)) datatype in postgre table. I had try with bool, char, integer datatype (C#) but that is also got same error.

Code For bulk data insertion


    public void BulkInsert(string connectionString, DataTable dataTable)
    {
        using (var npgsqlConn = new NpgsqlConnection(connectionString))
        {
            npgsqlConn.Open();
            var commandFormat = string.Format(CultureInfo.InvariantCulture, "COPY {0} {1} FROM STDIN BINARY", "logging.testtable", "(firstName,LastName,LogDateTime,RowStatus,active,id,paymentdone)");
            using (var writer = npgsqlConn.BeginBinaryImport(commandFormat))
            {
                foreach (DataRow item in dataTable.Rows)
                {
                   writer.WriteRow(item.ItemArray);
                }
            }

            npgsqlConn.Close();
        }
    }

DataTable Function 

private static void BulkInsert()
    {

        DataTable table = new DataTable();
        table.Columns.Add("firstName", typeof(String));
        table.Columns.Add("LastName", typeof(String));
        table.Columns.Add("LogDateTime", typeof(DateTime));
        table.Columns.Add("RowStatus", typeof(int));
        table.Columns.Add("active", typeof(bool));
        table.Columns.Add("id", typeof(long));
        table.Columns.Add("paymentdone", typeof(bool));
        var dataRow = table.NewRow();
        dataRow[0] = "Test";
        dataRow[1] = "Temp";
        dataRow[2] = DateTime.Now;
        dataRow[3] = 1;
        dataRow[4] = true;
        dataRow[5] = 10;
        dataRow[6] = true;
        table.Rows.Add(dataRow);

       BulkInsert(ConfigurationManager.ConnectionStrings["StoreEntities"].ConnectionString, table);
    }

Solution

  • This is probably happening because when Npgsql sees a boolean, its default is to sent a PostgreSQL boolean and not a BIT(1). When using binary COPY, you must write exactly the types PostgreSQL expects.

    One solution is probably to use .NET BitArray instead of boolean. Npgsql will infer PostgreSQL BIT() from that type and everything should work.

    But a safer solution is simply to call StartRow() and then to use the overload of Write() which accepts an NpgsqlDbType. This allows you to unambiguously specify which PostgreSQL type you want to send.