neisbut / Npgsql.Bulk

Helper for performing COPY (bulk insert and update) operation easily, using Entity Framework + Npgsql.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Core 3.1 Invalid cast from System.DBNull

KovtunV opened this issue · comments

Hello, in version 0.8.0 on Core 3.1 I have an exception after "Insert".

Invalid cast from 'System.DBNull' to 'System.Nullable`1[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]'.

It happens if I have a nullable navigation property:

public class Consumer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Transgas Transgas { get; set; }
    public int? TransgasId { get; set; }
}

public class Transgas
{
    public int Id { get; set; }
    public string Name { get; set; }
}

If I hide property "public Transgas Transgas { get; set; }" all will be okay

Test context:

   public class MyDb : DbContext
    {
        public DbSet<Consumer> Consumers { get; set; }
        public DbSet<Transgas> Transgases { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {   
         optionsBuilder.UseNpgsql("Host=127.0.0.1;Port=5432;Database=TestBulk;Username=postgres;Password=123;Timeout=120;Command Timeout=300");
        }
    }

Entry point:

  class Program
    {
        static void Main(string[] args)
        {
            var data = GetConsumers().ToArray();

            var db = new MyDb();
            var bulk = new NpgsqlBulkUploader(db);
            bulk.Insert(data); // Invalid cast from 'System.DBNul
        }

        static IEnumerable<Consumer> GetConsumers()
        {
            yield return new Consumer
            {
                Name = "My test name"
            };
        }
    }

Hi @KovtunV, thanks for posting this! Should be fixed this in 0.8.1, please check when possible.

@neisbut

Thanks but it still doesn't work. Now I have an exception like:

Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]'.

This is because of the nullable id.
For example:

var typeTo = typeof(int?);
var myId = 1078;
var res = Convert.ChangeType(myId, typeTo); // this exception

Before your fixing, I solved this problem by means of runtime method injection and replaced method ReadValue to

        public static object ReadValue(Type expectedType, NpgsqlDataReader reader, string columnName)
        {
            var value = reader[columnName];
            if (value == null)
                return value;

            var actual = value.GetType();
            if (actual == typeof(DBNull))
            {
                return null;
            }

            if (expectedType == actual)
                return reader[columnName];
            else if (actual == typeof(DateTimeOffset) && expectedType == typeof(DateTime))
                return ((DateTimeOffset)value).DateTime;
            else
            {
                var nullableSubtype = Nullable.GetUnderlyingType(expectedType);
                return Convert.ChangeType(value, nullableSubtype ?? expectedType);
            }
        }

If this is the true fix, I think you should add it

            else
            {
                var nullableSubtype = Nullable.GetUnderlyingType(expectedType);
                return Convert.ChangeType(value, nullableSubtype ?? expectedType);
            }

Oh, sorry, I forgot to check this case. Implemented in 0.8.1.1