3

While using a PostgreSQL database with Entity Framework on Mono using the packages Npsql and Npsql.EntityFramework I get an exception while trying to run Code First migrations from a Console app. The connection does work in the app and the database can be CRUD'ed programmatically.

The Context class looks as follows:

public class ZkContext : DbContext, IZkContext
{

    public ZkContext() : base("ZkTestDatabaseConnection")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // PostgreSQL uses schema public by default.
        modelBuilder.HasDefaultSchema("public");

    }

    public IDbSet<Crop> Crops { get; set; } 

}

Furthermore, there is a class Configuration that derives from DbMigrationsConfiguration<T> as follows:

public class Configuration : DbMigrationsConfiguration<ZkContext>
{
    public Configuration ()
    {
        AutomaticMigrationsEnabled = false;
        SetSqlGenerator("Npgsql", new PostgreSqlMigrationSqlGenerator());
    }
}

The PostgreSqlMigrationSqlGenerator class comes from this PostgreSqlMigrationSqlGenerator repository (the same error pops up with the default SqlGenerator so that code is not the problem).

I try to run the configuration from a console app as follows via this idea, which is possible since the PowerShell commands "are just thin wrappers over an underlying API":

var config = new Configuration();
var scaffolder = new MigrationScaffolder(config); //<= Here it breaks
var migration = scaffolder.Scaffold("Initial");

Unfortunately, add the MigrationScaffolder(config) statement this error pops up:

System.NotImplementedException has been thrown. MARS is not yet implemented!

Multiple Active Result Sets (MARS) are apparently not implemented in Mono yet. The class System.Data.SqlClient.SqlConnectionStringBuilder in the Mono framework is responsible. If you follow the link to the code you can see that on line 797 the exception is thrown:

case "MULTIPLEACTIVERESULTSETS":
    if (value == null) {
        _multipleActiveResultSets = DEF_MULTIPLEACTIVERESULTSETS;
        base.Remove (mappedKey);
    } else if ( DbConnectionStringBuilderHelper.ConvertToBoolean (value))
        throw new NotImplementedException ("MARS is not yet implemented!");
    break;

in the SetValue (string key, object value) method.

My question is: is there a way to put MARS off and get the Migration generator to not throw the exception?

/edit Appending ;MultipleActiveResultSets=False to the connection string does not help since it is not a valid property for PostgreSQL connection strings. Furthermore, setting Configuration.LazyLoadingEnabled = false; on the ZkContext context class does not help either.

/edit Call stack:

System.Data.SqlClient.SqlConnectionStringBuilder.SetValue (key="multipleactiveresultsets", value="True") in System.Data.SqlClient.SqlConnectionStringBuilder.set_Item (keyword="multipleactiveresultsets", value="True") in System.Data.Common.DbConnectionStringBuilder.ParseConnectionStringNonOdbc (connectionString="Data Source=.\SQLEXPRESS; Integrated Security=True; MultipleActiveResultSets=True;") in
System.Data.Common.DbConnectionStringBuilder.ParseConnectionString (connectionString="Data
Source=.\SQLEXPRESS; Integrated Security=True; MultipleActiveResultSets=True;"
) in
System.Data.Common.DbConnectionStringBuilder.set_ConnectionString (value="Data
Source=.\SQLEXPRESS; Integrated Security=True; MultipleActiveResultSets=True;") in
System.Data.SqlClient.SqlConnectionStringBuilder..ctor (connectionString="Data
Source=.\SQLEXPRESS; Integrated Security=True; MultipleActiveResultSets=True;") in
System.Data.Entity.Infrastructure.SqlConnectionFactory.CreateConnection
(nameOrConnectionString="ZkTestDatabaseConnection") in
System.Data.Entity.Internal.LazyInternalConnection.Initialize () in
System.Data.Entity.Internal.LazyInternalConnection.get_Connection () in
System.Data.Entity.Internal.LazyInternalContext.get_Connection () in
System.Data.Entity.Infrastructure.DbContextInfo..ctor (contextType={Zk.Models.ZkContext},
modelProviderInfo=(null), config={System.Data.Entity.Internal.AppConfig},
connectionInfo=(null), resolver=(null)) in
System.Data.Entity.Infrastructure.DbContextInfo..ctor (contextType={Zk.Models.ZkContext},
resolver=(null)) in
System.Data.Entity.Infrastructure.DbContextInfo..ctor (contextType={Zk.Models.ZkContext}) in
System.Data.Entity.Migrations.DbMigrator..ctor (configuration=
{Zk.Migrations.Configuration}, usersContext=(null),
existenceState=System.Data.Entity.Internal.DatabaseExistenceState.Unknown,
calledByCreateDatabase=false) in
System.Data.Entity.Migrations.DbMigrator..ctor (configuration=
{Zk.Migrations.Configuration}) in
System.Data.Entity.Migrations.Design.MigrationScaffolder..ctor (migrationsConfiguration=
{Zk.Migrations.Configuration}) in
Zk.Migrations.MigrationsTool.Main (args={string[0]}) in /home/erwin/zaaikalender
/Zk.Migrations/MigrationsTool.cs:23

The bold connection string is not the specified connection string.

Community
  • 1
  • 1
user2609980
  • 10,264
  • 15
  • 74
  • 143
  • Note: .NET is going cross-platform and open source; so no more Mono! Probably won't help you *today* though. – BradleyDotNET Nov 21 '14 at 20:21
  • Well it will be a collaboration between Mono and .NET, not a rebuild. Since the .NET core is open source now and Microsoft will be giving full support to Mono while working closely together, bugs and missing features can be more easily fixed and implemented. /Edit correction: it seems that Mono and .NET will stay separate? ([Source](http://www.theregister.co.uk/2014/11/12/release_microsoft_net_from_its_windows_chains_mono_and_xamarin_guy_miguel_de_icaza_on_open_source_net/)). Anyhow, maybe you see how to not get into that Case Statement above? :-) – user2609980 Nov 21 '14 at 20:30
  • just checking the obvious - do you have a `MultipleActiveResultSets` setting in your connection string config? – Rhumborl Nov 21 '14 at 20:33
  • Sorry, no. I'm not super familiar with the migration tools *or* mono's differences against .NET (other than lack of WPF :( ) so I won't be much use here. – BradleyDotNET Nov 21 '14 at 20:33
  • @Rhumborl I have updated my connectionstring by appending `MultipleActiveResultSets=False` (it is false by default) and this does not help. – user2609980 Nov 21 '14 at 20:40
  • Could you [file a bug](https://entityframework.codeplex.com/WorkItem/Create)? We (the EF team) should probably investigate why multiple result sets are active in this codepath. – bricelam Nov 24 '14 at 05:18
  • Hi @bricelam, I only now see the stack trace and that makes it clear that it takes the default connection string specified in the web.config. I think the error can be fixed in a similar fashion as [this question](http://stackoverflow.com/questions/12861458/entity-framework-connecting-to-sqlexpress-not-sql-compact). I don't think there is a bug. I'll let you know! – user2609980 Nov 24 '14 at 20:06
  • @bricelam Problem solved (code compiles and no more error). In the separate project the `app.config` needed the same code for `npgsql` connection. – user2609980 Nov 24 '14 at 20:39

1 Answers1

2

It was not necessary to disable MARS. What can be seen from the explicit stack trace is that my context used a default connection string. This happened because I was running migrations from a separate project in a console app.

When I copied some of the information in the web.config of the default project (where the DbContext resided) to the app.config of the console app the builder compiled.

The migrations are working (!) and the MARS error does not happen any more since the correct connection string is now taken.

Duplicated xml-configuration in app.config of migrations project:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" 
             type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.1.1, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
             requirePermission="false" />
  </configSections>
  <!-- <connectionStrings configSource="../Zk/ConnectionStrings.config" /> -->
  <connectionStrings>
    <clear />
    <add name="ZkTestDatabaseConnection" 
         connectionString="Server=localhost;Port=5432;Database=ZkTestDatabase;User Id=zktest;Password=broccoli;CommandTimeout=20;" 
         providerName="Npgsql" />
  </connectionStrings>
  <system.data>
    <DbProviderFactories>
      <add name="Npgsql Data Provider" 
           invariant="Npgsql" 
           description="Data Provider for PostgreSQL" 
           type="Npgsql.NpgsqlFactory, Npgsql" />
    </DbProviderFactories>
  </system.data>
  <entityFramework>
    <defaultConnectionFactory type="Npgsql.NpgsqlFactory, Npgsql" />
    <providers>
      <provider invariantName="Npgsql" 
                type="Npgsql.NpgsqlServices, Npgsql.EntityFramework" />
    </providers>
  </entityFramework>
</configuration> 
Kjartan
  • 18,591
  • 15
  • 71
  • 96
user2609980
  • 10,264
  • 15
  • 74
  • 143