How to Pass Full Sqlite Connection String to DbContext - c#

I am trying to pass the full connection string to DbContext constructor as an argument and I get this error:
Unable to complete operation. The supplied SqlConnection does not specify an initial catalog or AttachDBFileName.
And this is what I have tried:
public DatabaseContext() :base(#"Data Source=|DataDirectory|ComponentDatabase.sqlite") {}
Problem can't be about anything else but connection string because I was able to connect my database using connection string from App.config like this:
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" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<entityFramework>
<providers>
<provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
</providers>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
<connectionStrings>
<!-- use AppDomain.SetData to set the DataDirectory -->
<add name="MapDbConnectionStr" connectionString="Data Source=|DataDirectory|ComponentDatabase.sqlite" providerName="System.Data.SQLite" />
</connectionStrings>
<system.data>
<DbProviderFactories>
<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" />
<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" /></DbProviderFactories>
</system.data>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Data.SQLite" publicKeyToken="db937bc2d44ff139" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.105.2" newVersion="1.0.105.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Data.SQLite.EF6" publicKeyToken="db937bc2d44ff139" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.105.2" newVersion="1.0.105.2" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
DbContext
public DatabaseContext() :base("MapDbConnectionStr") {}
P.S. I know that App.config has a lot of unnecessary lines, yes.

As far as I am aware there isn't a Connection factory for the type of database you are trying to connect to.
You could write your own connection factory:
public class MySqlLiteConnectionFactory : IDbConnectionFactory
{
public DbConnection CreateConnection(string connectionString)
{
return new SQLiteConnection(connectionString);
}
}
now go and find the entry for defaulConnectionfactory in app.config and replace the line which specifies the type. At the moment thats going to read something like this:
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
change it to something like this:
<defaultConnectionFactory type="MyNamespace.MySQLiteConnectionFactory, MyAssemblyHere" />
You should now be able to correctly use the Context ctor (string connectionString).
There is another was of doing this without relying on appsettings EF 6 and onwards supports code-based configuration.
So you can do something with configurations that looks a bit like this:
DbConfiguration.Loaded += (_, a) =>
{
a.ReplaceService<DbProviderServices>((s, k) => new MyProviderServices(s));
a.ReplaceService<IDbConnectionFactory>((s, k) => new MyConnectionFactory(s));
};
Full details of this are documented here at microsoft:

Using the name from config file works because it can determine the provider type based on accompanying config provided. When using the connection string directly in the constructor it cannot determine that the connection string is for SQLite and assumes MSSQL so it is trying to use a SqlConnection. Hence the error message you encountered.
Take Note:
The connection to the database (including the name of the database)
can be specified in several ways. If the parameterless DbContext
constructor is called from a derived context, then the name of the
derived context is used to find a connection string in the app.config
or web.config file. If no connection string is found, then the name is
passed to the DefaultConnectionFactory registered on the Database
class. The connection factory then uses the context name as the
database name in a default connection string. (This default connection
string points to .\SQLEXPRESS on the local machine unless a different
DefaultConnectionFactory is registered.) Instead of using the derived
context name, the connection/database name can also be specified
explicitly by passing the name to one of the DbContext constructors
that takes a string. The name can also be passed in the form
"name=myname", in which case the name must be found in the config file
or an exception will be thrown. Note that the connection found in the
app.config or web.config file can be a normal database connection
string (not a special Entity Framework connection string) in which
case the DbContext will use Code First. However, if the connection
found in the config file is a special Entity Framework connection
string, then the DbContext will use Database/Model First and the model
specified in the connection string will be used. An existing or
explicitly created DbConnection can also be used instead of the
database/connection name.
Taken from the class remarks for DbContext
The last quoted sentence stands out...
An existing or explicitly created DbConnection can also be used
instead of the database/connection name.
You could consider using SQLiteConnection
public class DatabaseContext : DbContext {
public DatabaseContext()
:base(new SQLiteConnection(#"Data Source=|DataDirectory|ComponentDatabase.sqlite"), true) {
//...
}
//...
}

As i understood correctly it could be helpful, please use builder with db context options. I use SqlServer, hovewer there should be not a lot of changes.
var builder = new DbContextOptionsBuilder<MapDbContext>();
builder.UseSqlServer(ConfigurationManager.ConnectionStrings["MapDbConnectionStr"].ConnectionString), opt => opt.EnableRetryOnFailure());
var mycontext = new MapDbContext(builder.Options);
public MapDbContext(DbContextOptions<MapDbContext> options)
: base(options)
{ }
Hope it helps, Good luck.

Related

Entity Framework 6 with SQLite 1.0.108.0 query hangs forever

We have an x86-bit winforms application that is .Net 4.0 and using EF 6.2
and SQLite 1.0.108.0.
Application is running fine on most machines on some it just hangs forever when querying any table in sqlite db file.
We are able to create the context, but after calling the first query it just hangs.
Also, calling GC.WaitForPendingFinalizers() hangs forever too.
Also worth mentioning that using System.Data.SQLite.SQLiteConnection and System.Data.SQLite.SQLiteCommand works fine.
There are no prior calls to db through EF context, so there should not be any lingering connection to DB that is still not disposed.
My context class is:
public class MyClientContext : DbContext
{
static MyClientContext ()
{
Database.SetInitializer<MyClientContext >(new
CreateDatabaseIfNotExists<MyClientContext >());
Database.DefaultConnectionFactory = new EncryptedConnectionFactory();
}
public eReceiptPosClientContext(string connectionString)
: base(Database.DefaultConnectionFactory.CreateConnection(connectionString), true)
{
}
// DBsets here
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Mappings here
}
}
EF and SQLite configs in App.Config:
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
<parameters>
<parameter value="Data Source=(localdb)\v11.0; Integrated Security=True; MultipleActiveResultSets=True" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SQLite.EF6" />
<add name="SQLite Data Provider" invariant="System.Data.SQLite" description="Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
</DbProviderFactories>
</system.data>
Update:
I am sure now that it is an issue with Disposing the repository object. I think calling the object dispose is not disposing anything really.
Thats why calling GC.WaitForPendingFinalizers() hangs.
Below is how I create and use the repo:
using (var repo = new SettingsRepository(dbConnString))
{
repo.GetValue(HasValidReceiptsKey);
}
And inside GetValue():
return _db.Settings.Where(k => k.Key == key).FirstOrDefault();
Can it really be that the dispose is not working?
Or am I missing something.
Any help would be much appreciated.
Thank you,
Mousa Shawar

How can I change path to my DB file on App.config?

I am trying to use sql server mdf file in winForm using entity framwork 6, I do not want to install SQL Server in user's computer to use my winform application.
For this sake I added new ADO.NET entity model and choose sql database file,
now I am trying to access mdf file (which is in debug folder of my project) from App.config connection string
my Connection string is
<add name="miosystem_halqaEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string='data source=TOFIQ;attachdbfilename="C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\miosystem_halqa.mdf";integrated security=True;MultipleActiveResultSets=True;App=EntityFramework'" providerName="System.Data.EntityClient" />
and App.config is
<?xml version="1.0" encoding="utf-8"?>
<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>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<connectionStrings>
<add name="miosystem_halqaEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string='data source=TOFIQ;attachdbfilename="C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\miosystem_halqa.mdf";integrated security=True;MultipleActiveResultSets=True;App=EntityFramework'" providerName="System.Data.EntityClient" />
</connectionStrings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
The code is below for testing the connection
miosystem_halqaEntities db = new miosystem_halqaEntities();
private void Form1_Load(object sender, EventArgs e)
{
var j = db.ms_user.Where(x => x.user_id > 0).Select(x=>x.user_fname).ToList();
for (int i = 0; i < j.Count; i++)
{
label1.Text += j[i].ToString() + "\r";
}
}
I tried using ~ in my connection string but get the error
The underlying provider failed on Open.
<add name="miosystem_halqaEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string='data source=TOFIQ;attachdbfilename="~\miosystem_halqa.mdf";integrated security=True;MultipleActiveResultSets=True;App=EntityFramework'" providerName="System.Data.EntityClient" />
What I am missing in connection string ? how can i use relative path etc
From a relative path point of view, if the mdf file is in the debug folder of your project then you shouldn't need to specifiy a path in the connection string because your code will be running from that location. Try removing the ~\ from the connection string leaving just the filename.
However, even if the path is correct I'm not sure it's going to work anyway because the database instance TOFIQ referenced in the Data Source isn't going to exist on your client's machine. As Panagiotis said, I think you will need SQL Server Express on the client machine or host the file on a server that has SQL Server installed that the client has access to.

Why are the data providers different for code first and db first with Entity Framework

I'm a newbie for entity framework.
When I added code first and db first entities to my project,
I noticed that code first uses standart sql provider "System.Data.SqlClient"
and db first uses "System.Data.EntityClient" provider.
The classes generated for 2 different type is very similar, actually I did not notice any difference except "OnModelCreating" override from DbContext.
Code first :
<connectionStrings>
<add name="Model1" connectionString=""
providerName="System.Data.SqlClient" />
</connectionStrings>
Db First :
<connectionStrings>
<add name="PenCalcEntities" connectionString=""
providerName="System.Data.EntityClient" />
</connectionStrings>
1 ) Why is there a difference like that ? And altough the classes very similar , why code first does not work with EntityClient provider , and why db first does not work with SqlClient provider ?
2) Two type of approaches add "entityFramework" section to my config file like
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
When I removed this section , it also works well for two approaches.
What is the purpose of this section ?

SQL Server connection throw exception when using Entity Framework migration - add code snippet

I have a simple C# solution which has an entity class and a context class and also a console application which I use to test Entity Framework migration. But I always get this error:
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified).
Here is the connection string in the app.config (I put it in both console's app.config and context class's app.config):
<add name="ZzaDbConnectionString"
connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Zza;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite‌​;MultiSubnetFailover=False"
providerName="System.Data.SqlClient" />
I copied the connection string from "Connection string" property of the database from SQL Server ObjectExplorer so I suppose it is good.
Any suggestion why it always throws this exception?
I added entity class, context class and console class and hope this will have some clarification on my questions.
This is Entity class.
namespace Zza.Entities
{
public class Customer
{
public Guid Id { get; set; }
[MaxLength(50)]
public string FullName { get; set; }
}
}
This is Context class:
namespace Zza.Data
{
public class ZzaDbContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
}
}
This is console class:
namespace TestEFMigration
{
public class Program
{
static void Main(string[] args)
{
CreateDataBase();
}
private static void CreateDataBase()
{
var context = new ZzaDbContext();
context.Database.Initialize(false);
}
}
}
Console's app.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<connectionStrings>
<add name="ZzaDbConnectionString" connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Zza;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
And app.config of context class:
<?xml version="1.0" encoding="utf-8"?>
<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>
<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" />
</providers>
</entityFramework>
<connectionStrings>
<add name="ZzaDbConnectionString" connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Zza;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
Thanks.
I reduced connection strings.
As you are using localdb, it may have trouble with some of your parameters intended for full sql server (are you aware of it?)
Differences I found are:
connectionString="AttachDbFilename=|DataDirectory|\Zza.mdf;MultipleActiveResultSets=True;App=EntityFramework"
connectionString="Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite‌​;MultiSubnetFailover=False"
So, please try removing all options on second line and adding ones on top (AttachDbFilename can be a path to the mdf you want to use/create)
<add name="ZzaDbConnectionString"
connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Zza;Integrated Security=True;
AttachDbFilename=|DataDirectory|\Zza.mdf;MultipleActiveResultSets=True;App=EntityFramework;"
providerName="System.Data.SqlClient" />
EDIT: Ceck this
public class ZzaDbContext: DbContext
{
public ZzaDbContext()
: this("ZzaDbConnectionString")
{
}
// ...

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