Search code examples
npgsql

'NpgsqlBinaryImporter' does not contain a definition for 'Cancel'


As I write this, the documentation at https://www.npgsql.org/doc/copy.html#cancel says:

Import operations can be cancelled at any time by calling the Cancel() method on the importer object. No data is committed to the database before the importer is closed or disposed.

Export operations can be cancelled as well, also by calling Cancel().

I just updated my Npgsql package from 3.1.10 to 4.0.7, and now I get the error 'NpgsqlBinaryImporter' does not contain a definition for 'Cancel' for code similar to the following:

void WriteStuff(IEnumerable<RowInfo> enumerable, NpgsqlConnection conn)
{
    using (var writer = conn.BeginBinaryImport("COPY blah blah FROM STDIN (FORMAT BINARY)"))
    {
        try
        {
            foreach (var rowInfo in enumerable)
            {
                writer.StartRow();
                writer.Write(...); // blah blah
            }
            writer.Close();
        }
        catch
        {
            writer.Cancel();
            throw;
        }
    }
}

It looks like this commit made Cancel() private.

So what is the correct way to cancel a bulk operation now? Do I need to wrap it in a transaction?

[And given the answer, I should just get rid of the try-catch code in the above code and just let the exception happen. Also the call to writer.Close() should change to writer.Complete(). ]


Solution

  • Npgsql 4.0 changed the COPY API around cancellation in a significant way, see the release notes.

    In a nutshell, you must now explicitly call Complete() on NpgsqlBinaryImporter in order to commit the import; disposing it without calling Complete() will cancel the operation. This was done in order to make sure that exceptions don't cause a commit, and is aligned with how .NET TransactionScope work.

    I'll update the documentation on this - thanks for pointing it out!