How to disable MARS and circumvent “MARS is not ye

2019-01-28 08:32发布

问题:

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.

回答1:

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>