Question

I'm using an embedded Firebird database with code first (Entity Framework 6). The first time the application runs, it works fine: the database gets created and the data gets inserted. But every time it runs after that, it throws the following exception:

An exception of type 'System.NotSupportedException' occurred in FirebirdSql.Data.FirebirdClient.dll but was not handled in user code

Additional information: Unknown data type

The project includes the following NuGet packages:

  • EntityFramework [6.0.2]
  • Firebird ADO.NET Data provider (Entity Framework 6) [4.1.0.0]

I added the DbProviderFactories and FirebirdSql.Data.FirebirdClient provider to App.config as described here.

I also added the Firebird DLLs to the project and set them to copy to the output directory:

  • fbembed.dll
  • ib_util.dll
  • icudt30.dll
  • icuin30.dll
  • icuuc30.dll

I have not enabled code first migrations (though the __MigrationHistory table still gets created for some reason).

Here's the code:

class Program
{
    static void Main(string[] args)
    {
        Database.SetInitializer<FirebirdDbContext>(new CreateDatabaseIfNotExists<FirebirdDbContext>());
        string connectionString = "server type=Embedded;user id=sysdba;password=masterkey;role name=RDB$ADMIN;character set=UTF8;initial catalog=test.fdb";

        using (var context = new FirebirdDbContext(connectionString))
        {
            context.Users.Add(new User()
                { Created = DateTime.Now,
                    Name = "smith" });
            context.SaveChanges();
        }
    }
}

class User
{
    [Key]
    public DateTime Created { get; set; }

    public string Name { get; set; }
}

class FirebirdDbContext : DbContext
{
    public FirebirdDbContext(string connString)
        : base(new FbConnection(connString), true) { }

    public DbSet<User> Users { get; set; }
}

class MyConfiguration : DbConfiguration
{
    public MyConfiguration() 
    {
        SetDefaultHistoryContext((c, s) => new SmallKeyHistoryContext(c, s));
    }
}

class SmallKeyHistoryContext : HistoryContext
{
    public SmallKeyHistoryContext(DbConnection existingConnection, string defaultSchema)
        : base(existingConnection, defaultSchema) { }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        // HACK: Make this column smaller to avoid the following error:
        // key size exceeds implementation restriction for index "PK___MigrationHistory"
        modelBuilder.Entity<HistoryRow>().Property(h => h.ContextKey).HasMaxLength(53).IsRequired();
    }
}

The exception gets thrown on the context.Users.Add(...) line.

Here's the stack trace:

at FirebirdSql.Data.Common.DbValue.GetBytes() in c:\Users\Jiri\Documents\devel\NETProvider\working\NETProvider\source\FirebirdSql\Data\Common\DbValue.cs:line 315
at FirebirdSql.Data.Client.Common.XsqldaMarshaler.MarshalManagedToNative(Charset charset, Descriptor descriptor) in c:\Users\Jiri\Documents\devel\NETProvider\working\NETProvider\source\FirebirdSql\Data\Client\Common\XsqldaMarshaler.cs:line 121
at FirebirdSql.Data.Client.Native.FesStatement.Execute() in c:\Users\Jiri\Documents\devel\NETProvider\working\NETProvider\source\FirebirdSql\Data\Client\Native\FesStatement.cs:line 355
at FirebirdSql.Data.FirebirdClient.FbCommand.ExecuteCommand(CommandBehavior behavior, Boolean returnsSet) in c:\Users\Jiri\Documents\devel\NETProvider\working\NETProvider\source\FirebirdSql\Data\FirebirdClient\FbCommand.cs:line 1246
at FirebirdSql.Data.FirebirdClient.FbCommand.ExecuteReader(CommandBehavior behavior) in c:\Users\Jiri\Documents\devel\NETProvider\working\NETProvider\source\FirebirdSql\Data\FirebirdClient\FbCommand.cs:line 566
at FirebirdSql.Data.FirebirdClient.FbCommand.ExecuteDbDataReader(CommandBehavior behavior) in c:\Users\Jiri\Documents\devel\NETProvider\working\NETProvider\source\FirebirdSql\Data\FirebirdClient\FbCommand.cs:line 666
at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<>c__DisplayClassb.<Reader>b__8()
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TInterceptionContext,TResult](Func`1 operation, TInterceptionContext interceptionContext, Action`1 executing, Action`1 executed)
at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)

The stack trace points to the Firebird library (right here). I tried tracing the code backwards but I can't tell if GetBytes() is called for all fields or just byte[] fields. (I initially thought that it might be related to the __MigrationHistory.Model field in the database, but the error still occurs if that table is empty. However, I don't want my speculation to cause misdirection.)

I could hack around the issue, but I'd really like to understand it. Does anyone know what's happening here?

Was it helpful?

Solution

I Had the same problem, The Entity initializer is bugged with Firebird embedded:

Database.SetInitializer<FirebirdDbContext>(new CreateDatabaseIfNotExists<FirebirdDbContext>()); 

is the problem, change it to:

Database.SetInitializer<FirebirdDbContext>(null);

But it will not create the database for you. You could check if the database file existis then change de initializer.

or you can create your initializer that does tha same, and works:

public class MyCreateDatabaseIfNotExists : IDatabaseInitializer<FirebirdDbContext>
{
    public void InitializeDatabase(FirebirdDbContext context)
    {
        if (!context.Database.Exists())
        {
            context.Database.Create();
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top