Postgresql npgsql first connection takes too long - c#

I am new to Postgresql. I am tring to use Postgresql with entity framework6, using npgsql.
I already have a database. I am using "Code First form database" option.
The problem is that the first time a query is executed, it takes me lots of time to execute it. I think that is when the connection is opened for the first time.
I created this simple example with the problem (TestJSONB is DbContext):
class Program
{
static void Main(string[] args)
{
TestQuery();
TestQuery();
}
private static void TestQuery()
{
using (DALJSONB.TestJSONB dataModel = new DALJSONB.TestJSONB())
{
var query1 =
dataModel.Database.SqlQuery<int>(
#"
SELECT 1;
");
query1.ToList();
var query2 =
dataModel.Database.SqlQuery<int>(
#"
SELECT 1;
");
query2.ToList();
}
}
}
The first execution times of TestQuery() are something like:
query1.ToList() - 2348ms
query2.ToList() - 2ms
The second execution times of TestQuery() are something like:
query1.ToList() - 19ms
query2.ToList() - 2ms
My 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.2" />
</startup>
<connectionStrings>
<add name="TestJSONB" connectionString="Host=x.x.x.x;Username=x;Password=x;Persist Security Info=True;Database=TestJSONB" providerName="Npgsql" />
</connectionStrings>
<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="Npgsql" type="Npgsql.NpgsqlServices, EntityFramework6.Npgsql" />
</providers>
</entityFramework>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Npgsql" publicKeyToken="5d8b90d52f46fda7" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.2.1.0" newVersion="3.2.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Is it possible to decrease this time?
Thanks in advance.

This very likely has nothing to do with PostgreSQL or Npgsql, but rather with Entitt Framework itself starting up, building your model etc. try to connect to your database without EF (I.e. just creating an NpgsqlConnection and opening it) and you should see it runs pretty quickly.
It's common for EF applications to send sa sort of dummy warm-up query before actually servicing user calls, precisely to avoid this significant first-time delay.

Related

How to Pass Full Sqlite Connection String to DbContext

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.

Exception thrown while defining a query and connecting to Entity Framwork

The exception that was thrown was
"“The invocation of the constructor on type 'TestWPF.MainWindow' that
matches the specified binding constraints threw an exception.”"
Which I have googled and found this and several like it. All of which say to add <startup useLegacyV2RuntimeActivationPolicy="true" /> to you configuration file.
I have a method called GetCustomers:
void GetCustomers()
{
var context = new ContactTestEntities();
var query = from c in context.ContactTs
select c;
Listbox.ItemsSource = query.ToList();
}
It will throws the exception when on var query = from c in context.Contacts select c;
my config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="True" />
<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="ContactTestEntities"
connectionString="metadata=res://*/ContactTest.csdl|res://*/ContactTest.ssdl|res://*/ContactTest.msl;provider=System.Data.SqlClient;
provider connection string="data source=SQL;
initial catalog=ContactTest;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
<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>
</configuration>
please tell me if you see something incorrect here. thank you
Okay, after an hour of digging I figured out that there wasn't anything wrong with the code. The problem was that I didn't have the config file in the startup file. So that is the answer put your connection string into the startup file.

EF 6 with System.Data.SQlite SaveChanges() not working?

So I just started using System.Data.Sqlite with entity framework 6 (downloaded the latest System.Data.Sqlite from Nuget, version 1.0.91.0)
After some configuration and code, I found out that I can read from the database but somehow write is not working.
Here's my code:
using (var context = new InternalDbContext())
{
var demo = context.DemoEntities.Where(d => d.ID == 1).FirstOrDefault();
demo.Name = "TestTest";
context.DemoEntities.Add(new Demo { Name = "Test" });
context.SaveChanges();
}
Basically after SaveChanges, nothing was updated in the DB. However I can read fro the DB with the data I manually populated via SQlite admin tool.
Here's my DB schema:
Table name :Demo
Field: ID - Integer Primary Key AutoIncrement
Field: Name - VARCHAR(256)
Here's my classes
public class InternalDbContext : DbContext
{
public DbSet<Demo> DemoEntities { get; set; }
public InternalDbContext()
{
// Turn off the Migrations, (NOT a code first Db)
Database.SetInitializer<InternalDbContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Database does not pluralize table names
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
[Table("Demo")]
public class Demo
{
public long ID { get; set; }
public string Name { get; set; }
}
App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="common">
<section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
</sectionGroup>
<!-- 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>
<common>
<logging>
<factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net">
<arg key="configType" value="FILE-WATCH" />
<arg key="configFile" value="log4net.config" />
</factoryAdapter>
</logging>
</common>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Common.Logging" publicKeyToken="af08829b84f0328e" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.13.0" newVersion="1.2.13.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<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" />
<provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
</providers>
</entityFramework>
<connectionStrings>
<add name="InternalDbContext" connectionString="Data Source=.\testdb.sqlite" providerName="System.Data.SQLite.EF6" />
</connectionStrings>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SQLite.EF6" />
<add name="SQLite Data Provider" invariant="System.Data.SQLite.EF6" description="Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
</DbProviderFactories>
</system.data>
</configuration>
If anyone could point me to the right direction, that'd be fantastic, thanks so much
Nick
Your ./bin/Debug/ folder should contain a copy of your testdb.sqlite DB. That should have the changes.

MySql exception with EF5 and Winform

I'm trying to create a MySql Db with EF5 , so I have my dbSet and My SqlContext class, but when I run the program throws this exception
I have this code in my 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 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
</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.7.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
<connectionStrings>
<add name="ConnectionStringName" connectionString="server=localhost;Database=auth;uid=root;pwd=1234;" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="MySql.Data" publicKeyToken="c5687fc88969c44d" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.7.4.0" newVersion="6.7.4.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
and MySqlContext.cs
public class MySqlContext : System.Data.Entity.DbContext
{
public System.Data.Entity.DbSet<LoginModel> LoginModel { get; set; }
//public System.Data.Entity.DbSet<Roles> Roles { get; set; }
public MySqlContext()
: base("ConnectionStringName")
{ }
}
I'm using Entity Framework 5 , MySqlConector 6.7.4.0, Visual Studio 2012. Hope you guys can help me with this!
I found the answer with the post that user2453734 pointed EF5 Getting this error message: Model compatibility cannot be checked because the database does not contain model metadata and made a changes in the SetInitializer in Program.cs and I changed
this:
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MySqlContext>());
into this:
Database.SetInitializer<MySqlContext>(new DropCreateDatabaseIfModelChanges<MySqlContext>());
now it works!

Error after updgrading from EF 5 to EF 6.0.2

After upgrading from EF 5 to EF 6.0.2 I'm getting this error when executing the Update-Database command from the Package Manager Console:
Could not load file or assembly 'System.Web.Helpers, Version=3.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its
dependencies. The system cannot find the file specified.
Everything worked just fine before the upgrade.
This is my app.config:
<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>
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=.;Initial Catalog=aspnet-CodeFirst-Test;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<roleManager enabled="true" defaultProvider="SimpleRoleProvider">
<providers>
<clear />
<add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
</providers>
</roleManager>
<membership defaultProvider="SimpleMembershipProvider">
<providers>
<clear />
<add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<qualifyAssembly partialName="WebMatrix.WebData" fullName="WebMatrix.WebData, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</assemblyBinding>
</runtime>
<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>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
This is my Configuration.cs file:
public Configuration()
{
Database.SetInitializer<DataContext>(new DropCreateDatabaseAlways<DataContext>());
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(DataContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
SeedMembership(context);
}
I read that SimpleMembershipProvider got 'replaced' with Identity. Not sure if that is related to this error. But if anyone knows a tutorial how to do the migration, I'd love to have a link of that.
Also the database layer is a class lib project. There is no MVC installed in there.
Try adding this to your web.config under runtime section:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
And System.Web.Helpers should be referenced from your project as well

Categories