Using EF DbContext with mysql and sql in the same project - c#

I'm working on an ASP.net MVC project using EF in combination with MySql. Now this works just fine on its own but I also want to reference another class library that uses EF with SQL.
When I reference the library EF seems to get confused on what provider to use for each DbContext.
On my MySql DbContext I have the following attribute in order to tell EF this DbContext should be handled by the MySql provider:
[DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]
Now on the SQL DbContext, I have no attribute. Should I place one on there and if so which one?
Currently, I get the following error:
The default DbConfiguration instance was used by the Entity Framework
before the 'MySqlEFConfiguration' type was discovered. An instance of
'MySqlEFConfiguration' must be set at application start before using
any Entity Framework features or must be registered in the
application's config file.
This is pretty straightforward since the SQL context is used before the MySql one but I can't seem to find a fix on this.
What would be 'Best Practice' on handling this? Or is this something that I should avoid, combining 2 DbContexts in the same project?
MySql DbContext
[DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]
public class MySqlContext : DbContext
{
public MySqlContext() : base("name=MySqlContext")
{
this.Configuration.LazyLoadingEnabled = false;
}
//DbSets....
}
SQL DbContext
public class SqlContext : DbContext
{
public SqlContext() : base("name=SqlContext")
{
Configuration.LazyLoadingEnabled = false;
}
//DbSets....
}
Web.config:
<connectionStrings>
<add name="SqlContext" connectionString="some connectionString" providerName="System.Data.SqlClient" />
<add name="MysqlContext" connectionString="some connectionString" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"></provider>
</providers>
</entityFramework>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+" />
</compilers>
</system.codedom>
<system.data>
<DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient" />
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
I see on the DbProviderFactories it's only saying Mysql.

It's not important that how many DbContexts you have(In entity framework 6). Just put connection strings in appConfig or webConfig of startup project.
Example of appConfig with two connectionString with Ef 6.01 & Sql Server and My SQL
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="MySqlDB" connectionString="Your My SQL ConnectionString" providerName="My Sql Provider" />
<add name="SqlDB" connectionString="Your SQL ConnectionString" providerName="Sql Provider" />
</connectionStrings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework">
<parameters>
<parameter value="System.Data.SqlServerCe.4.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlServerCe.4.0" type="System.Data.Entity.SqlServerCompact.SqlCeProviderServices, EntityFramework.SqlServerCompact" />
</providers>
</entityFramework>
MySql DbContext
public class MySqlContext : DbContext
{
public MySqlContext() : base("MySqlDB")
{
this.Configuration.LazyLoadingEnabled = false;
}
//DbSets....
}
SQL DbContext
public class SqlContext : DbContext
{
public SqlContext() : base("SqlDB")
{
Configuration.LazyLoadingEnabled = false;
}
//DbSets....
}

Related

Is it possible to get rid of app.config depedency?

We upgraded a .Net Framework 4.5 project to .Net Framework 4.8 and some new things showed up in our app.config-file.
Is the code below (from app.config) necessary for MySQL and EntityFramework etc to work correctly?
Also, is it possible to accomplish the same thing as the code below programmatically, so that we can get rid of the app.config dependency?
We've tried to just remove the code below, but that resulted in our service not being able to start.
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6" />
</providers>
</entityFramework>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<system.data>
<DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient" />
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory,MySql.Data" />
</DbProviderFactories>
</system.data>
<system.web>
<membership defaultProvider="ClientAuthenticationMembershipProvider">
<providers>
<add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=<PUBLICKEY>" serviceUri="" />
</providers>
</membership>
<roleManager defaultProvider="ClientRoleProvider" enabled="true">
<providers>
<add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=<PUBLICKEY>" serviceUri="" cacheTimeout="86400" />
</providers>
</roleManager>
</system.web>
For the EntityFramework
There is a specific guide on Microsoft documentations stating that from EF6 onwards it can be done. Check here
Effectively the steps are the following:
Create only one DbConfiguration class for your application. This class specifies app-domain wide settings.
Place your DbConfiguration class in the same assembly as your DbContext class. (See the Moving DbConfiguration section if you want to change this.)
Give your DbConfiguration class a public parameterless constructor.
Set configuration options by calling protected DbConfiguration methods from within this constructor.
Example:
[DbConfigurationType(typeof(MyDbConfiguration))]
public class MyContextContext : DbContext
{
}
For the supported runtime
This has already been covered:
What happens if I remove the auto added supportedRuntime element?

Cannot set ProviderService in configuration

I am trying to move my app.config ef settings to code.
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
</configSections>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework">
<parameters>
<parameter value="System.Data.SqlServerCe.4.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="System.Data.SqlServerCe.4.0"
type="System.Data.Entity.SqlServerCompact.SqlCeProviderServices, EntityFramework.SqlServerCompact" />
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SqlServerCe.4.0" />
<add name="Microsoft SQL Server Compact Data Provider 4.0"
invariant="System.Data.SqlServerCe.4.0"
description=".NET Framework Data Provider for Microsoft SQL Server Compact"
type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
</DbProviderFactories>
</system.data>
</configuration>
Currently all I was able to set is the defaultConnectionFactory:
public class SqlServerCompactConfiguration : DbConfiguration
{
public SqlServerCompactConfiguration()
{
SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.SqlCeConnectionFactory("System.Data.SqlServerCe.4.0"));
SetProviderFactory("System.Data.SqlServerCe.4.0", new System.Data.SqlServerCe.SqlCeProviderFactory());
SetProviderServices("System.Data.SqlServerCe.4.0", new System.Data.Entity.SqlServerCompact.SqlCeProviderServices());
SetProviderServices("System.Data.SqlClient", new System.Data.Entity.SqlServer.SqlProviderServices());
}
}
For the last 2 lines I am getting the following error:
'SqlCeProviderServices' does not contain a constructor that takes 0 arguments'
I got no idea what to add here... Intellisense is showing nothing an so is the class when I use GoToDefinition there is no constructor...
Usually such service classes are implemented as singletons.
For instance, SqlProviderServices class contains the following:
//
// Summary:
// The Singleton instance of the SqlProviderServices type.
public static SqlProviderServices Instance { get; }
I can't check now, but I'm pretty sure SqlProviderService class has something similar.

MySql EF6 with IdentityDbContext

I try to use MS Identity with an MySql Databse and Code-First.
My DbContext Class:
[DbConfigurationType(typeof(MySqlEFConfiguration))]
public class TestDbContext : IdentityDbContext<ApplicationUser>
{
public TestDbContext()
{
}
public TestDbContext(string cnString)
: base(cnString)
{
}
}
My App Config:
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="TestDbContext" providerName="MySql.Data.MySqlClient" connectionString="server=localhost;port=3306;database=test;uid=root;password=root"/>
</connectionStrings>
<entityFramework codeConfigurationType="MySql.Data.Entity.MySqlEFConfiguration, MySql.Data.Entity.EF6">
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
</defaultConnectionFactory>
<providers>
<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6, Version=6.9.7.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient" />
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.7.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
</configuration>
If i use the normal DbContext its works with Code-First Migrations. But if i change to IdentityDbContext and i try to "Update-Database" i get the following Error:
Failed to set Database.DefaultConnectionFactory to an instance of the
'System.Data.Entity.Infrastructure.LocalDbConnectionFactory,
EntityFramework' type as specified in the application configuration.
See inner exception for details.
How can i get MS Identity to work with MySql?
Ok i have change the DefaultConnectionFactory to
<defaultConnectionFactory type="MySql.Data.Entity.MySqlConnectionFactory, MySql.Data.Entity.EF6" />
but now i get another Error:
Format of the initialization string does not conform to specification starting at index 0.
Ok i get the Database Connection to work but the Identity Tables such as aspnetuser won't create automaticly.

SQLite: Entity Framework 6 - Wrong DbProviderFactory

I'm going bonkers with this.
I have a standard C# console application, with EF 6.1.3 and SQLite 1.0.97.0. I've set up my app.config to connect to the SQLite database using standard ADO, which works:
static void StandardConnection()
{
try
{
SQLiteConnection db = new SQLiteConnection(ConfigurationManager.ConnectionStrings["StudioContext"].ConnectionString);
db.Open();
Console.WriteLine("Connected");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
But for the love of me, I can't get EF to connect to this database. I have tried every single solution I could read up on, but every time I try to connect, I find the DBProviderFactory always points to {System.Data.SqlClient.SqlClientFactory}. It is driving me insane.
Following, my DbContext class:
public class SqliteContext: DbContext
{
public SqliteContext()
: base(ConfigurationManager.ConnectionStrings["StudioContext"].ConnectionString)
{
Database.SetInitializer<SqliteContext>(null);
}
}
I don't want code first enabled, so disabled it here as this is off an existing application, being ported from PHP to C# and we have to work with the database as it is currently.
The code that's trying to connect:
static void EntityFrameworkConnection()
{
try
{
using (var db = new SqliteContext())
{
if (db.Database.Connection.State == System.Data.ConnectionState.Closed)
{
db.Database.Connection.Open();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Very basic, open an instance of the context, check the state and connect if closed, this step is not required as I understand that EF will open the connection, if closed, when doing something like a save, for example, I'm just trying to get the DB to connect.
My app.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="StudioContext" connectionString="Data Source=.\studio.db" providerName="System.Data.SQLite" />
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6, Version=1.0.97.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" />
<provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6, Version=1.0.97.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" />
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SQLite" />
<add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite, Version=1.0.97.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" />
<remove invariant="System.Data.SQLite.EF6" />
<add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6, Version=1.0.97.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" />
</DbProviderFactories>
</system.data>

Manually opening an EntityConnection to SQLite database causes ProviderIncompatibleException

For integration testing purposes I'd like to manually create and open an EntityConnection in the test fixture set up. This fails with the following exception when calling the Open() method:
System.Data.ProviderIncompatibleException : A null was returned after calling the 'GetService' method on a store provider instance of type 'System.Data.SQLite.EF6.SQLiteProviderFactory'. The store provider might not be functioning correctly.
I'm using the same connection string which is also used when EF takes care about connection opening. If I run the same test suite with automatic connection handling by EF it works.
...
[TestFixtureSetUp]
public void FixtureSetUp()
{
// Setup database
// Setup data access
...
var ec = new EntityConnection([ConnectionString]);
ec.StoreConnection.Open(); --> WORKS!!
ec.Open(); -> Throws
}
...
The connection string looks like the following:
metadata=res://*/Test.TestModel.csdl|res://*/Test.TestModel.ssdl|res://*/Test.TestModel.msl;provider=System.Data.SQLite;provider connection string="data source=C:\Test\tmp4C80.tmp;read only=False;pooling=False;failifmissing=True;synchronous=Full;datetimekind=Utc;enlist=True;setdefaults=False;datetimeformat=ISO8601;journal mode=Off;cache size=4194304"
The app.config for the NUnit assembly is the following
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework"
type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</configSections>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient"
type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="System.Data.SQLite"
type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
</providers>
</entityFramework>
<!-- Register protable database data providers -->
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SQLite" />
<add name="SQLite Data Provider" invariant="System.Data.SQLite"
description=".Net Framework Data Provider for SQLite"
type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6, Version=1.0.94.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" />
</DbProviderFactories>
</system.data>
</configuration>
Beside NUnit for testing, I'm using Entity Framework 6.1.1 and System.Data.SQLite 1.0.94.0.
Edit: The strange thing is that opening the store connection of the provided entity connection manually works...
I found out that I used the EntityConnection from System.Data.Entity instead of the EntityFramework assembly.

Categories