Executing EFcore Migrations inside a .NETStandard Library project - entity-framework

My question is basically: is it possible to use Entity Framework Core (and migrations) inside a .NET Standard 2.0 library project? (not a core project)
I currently have 2 projects:
ASP.NET Core main project: I don't want anything with databases or EF inside this project, so I added a reference to the .NETstandard2.0 DAL project
.NETStandard2.0 data access layer project: EF Core with database migrations project for accessing the database. The main project uses this project to get data from the database.
For the .NETStandard DAL project, I use the following settings and classes: the .csproj file contains the dependencies for EF and migrations:
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
</ItemGroup>
After calling dotnet restore, I created a DbContext descendant:
class MyTestContext: DbContext
{
public MyTestContext(DbContextOptions<MyTestContext> options) : base(options)
{
}
public DbSet<Class1> Class1Table { get; set; }
}
And added a DbContextFactory with IDesignTimeDbContextFactory like:
class DbContextFactory : IDesignTimeDbContextFactory<MyTestContext>
{
public MyTestContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<MyTestContext>();
builder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=efmigrations2017;Trusted_Connection=True;MultipleActiveResultSets=true",
optionsBuilder => optionsBuilder.MigrationsAssembly(typeof(MyTestContext).GetTypeInfo().Assembly.GetName().Name));
return new MyTestContext(builder.Options);
}
}
Okay, so far everything works fine and the .NETStandard project builds successfully.
Now I want to create my first migration by executing:
dotnet ef migrations add InitialCreate
This throws an error:
If I understand the error message correctly, EF Core can only be used in .NET Core and .NET Framework projects and NOT in .NETStandard projects?
If that is true, how can I separate the EF database logic from my other applications?
If not, how can I get the migrations to work?
Thank you in advance

You have two options.
One: Use your ASP.NET Core project as the startup project.
dotnet ef migrations add InitialCreate --startup-project ..\MyWebApplication
Two: Cross-target .NET Core in your class library. (Edit the *.csproj)
<PropertyGroup>
<!-- Note: This property name becomes plural. -->
<TargetFrameworks>netcoreapp2.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>

Related

How to consume a postgresql database from a net core api

Hello I want to connect my web API to a postgresql database but I have no idea where to start.
To use the Npgsql EF Core provider, you could following below steps:
1.add a dependency on Npgsql.EntityFrameworkCore.PostgreSQL with correct version.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.0.0" />
</ItemGroup>
</Project>
2.Set your own connection string in appsettings.json
"ConnectionStrings": {
"DbConnection": "User ID =postgres;Password=123456;Server=localhost;Port=5432;Database=MyTestdatabase;Integrated Security = True; Pooling=true"
},
3.In startup.cs ,register the dbContext with
services.AddDbContext<ApplicationDbContext>(opt =>
opt.UseNpgsql(Configuration.GetConnectionString("DbConnection")));
Or refer to http://www.npgsql.org/efcore/

Migration for Sequence not working on ASP.NET Core 2.1

I am using these packages:
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.2" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.1" />
My code:
// generate id
modelBuilder.HasSequence("UNIQUEIdGenerator", schema: "public")
.StartsAt(2000000000)
.IncrementsBy(1);
// TestId is not primary key
modelBuilder.Entity<ModelTest>()
.Property(d => d.TestId)
.HasDefaultValueSql("CONCAT('PREFIX', NEXTVAL('\"UNIQUEIdGenerator\"'))");
When I do migration it get success without any error, but when I open PGADMIN and navigate to the database and check the sequence under public schema, it doesn't show me an UNIQUEIdGenerator sequence.
**Note:- Table ModelTest was already there, when i did migration for this sequence
I was able to figure out the solution ("Work Around"). If I delete all migration files and regenerate all the migrations file and then update the db it work fine.
Step 1:- delete all the migration file + snapshot file
Step 2:- generate migration files dotnet ef migrations add
Step 3:- dotnet ef migrations script
Now if you search the output it will show you "Create Sequence" sql command, which was missing when i was trying to do with previously.

System.NotSupportedException: Unable to determine the provider name for provider factory of type 'System.Data.SqlClient.SqlClientFactory'

I am using EF6 with Asp.net core and I am getting error when I call to db through dbcontext :
System.NotSupportedException: Unable to determine the provider name for provider factory of type 'System.Data.SqlClient.SqlClientFactory'. Make sure that the ADO.NET provider is installed or registered in the application config.
at System.Data.Entity.Utilities.DbProviderFactoryExtensions.GetProviderInvariantName(DbProviderFactory factory)
at System.Data.Entity.Infrastructure.DependencyResolution.DefaultInvariantNameResolver.GetService(Type type, Object key)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at System.Linq.Enumerable.SelectArrayIterator`2.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Func`2 predicate, Boolean& found)
at System.Data.Entity.Infrastructure.DependencyResolution.ResolverChain.GetService(Type type, Object key)
at System.Linq.Enumerable.SelectArrayIterator`2.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Func`2 predicate, Boolean& found)
at System.Data.Entity.Infrastructure.DependencyResolution.ResolverChain.GetService(Type type, Object key)
at System.Data.Entity.Infrastructure.DependencyResolution.CompositeResolver`2.GetService(Type type, Object key)
at System.Data.Entity.Infrastructure.DependencyResolution.DbDependencyResolverExtensions.GetService[T](IDbDependencyResolver resolver, Object key)
at System.Data.Entity.Utilities.DbConnectionExtensions.GetProviderInvariantName(DbConnection connection)
at System.Data.Entity.Internal.InternalConnection.get_ProviderName()
at System.Data.Entity.Internal.DefaultModelCacheKeyFactory.Create(DbContext context)
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.Initialize()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
at CoreWithEF.controllers.SampleController.GetStudentDetails() in C:\Users\biradm1\Documents\Visual Studio 2017\Projects\CoreWithEF\CoreWithEF\controllers\SampleController.cs:line 27
at lambda_method(Closure , Object , Object[] )
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()} System.NotSupportedException
The error Unable to determine the provider name... can indicate the .csproj for the Core project is not set correctly per the instructions on Get Started with ASP.NET Core and Entity Framework 6.
In my case I was working with Core 2.2 project and trying to leverage Entity Framework 6 from .Net Framework 4.7.1 class library, but failed to change the Core .csproj file from <TargetFramework>netcoreapp2.2</TargetFramework> to <TargetFramework>net471</TargetFramework>.
When I finally made the target framework change, the next error to appear was Microsoft.AspNetCore.All 2.2.1 is not compatible with net471 (.NETFramework,Version=v4.7.1). I removed the NuGet Microsoft.AspNetCore.All package, which then created a lot of missing reference build errors.
To resolve the build errors I had to google the missing type to find the assembly name, add that specific NuGet package, rebuild, then keep repeating the process until all of my build errors were resolved.
Every project is different, but here were the packages I had to add to fix my build issues after removing Microsoft.AspNetCore.All:
<PackageReference Include="EntityFramework" Version="6.2.0" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.HttpsPolicy" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.5.0" />
After build issues were resolved and the project built successfully, my DotNet Core 2.2 API was able to return data using Entity Framework 6 from the class library project.
To summarize, the System.NotSupportedException occurred because the generated Entity Framework classes (in the .NET Framework 471 class library) were being accessed by the DotNet Core version of Entity Framework and not the .NET Framework 4.7.1 version of Entity Framework.
Before making the changes listed above, evaluating System.Data.Common.DbProviderFactories.GetFactoryClasses().Rows in the Immediate debug window showed an empty collection of providers. After making the changes, the Factory Classes included the Odbc, OleDb, Oracle, SqlServer providers.
More specifically if you evaluate the rows individually, you should see the providers are from the Full .NET Framework.
For example: System.Data.Common.DbProviderFactories.GetFactoryClasses().Rows[3].ItemArray (for me) showed it came from "System.Data.SqlClient.SqlClientFactory, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”.
update both project EntityFramework Package
for example 6.4.4 version
As stated at previous answer: Entity Framework 6 doesn't support .NET Core. If you need cross-platform features you will need to upgrade to Entity Framework Core.
You can try NHibernate for .Net Core projects.

Database-First, Npgsql setup error Configuration system failed to initialize

I'm attempting to setup EF Core in my Npgsql database application. I am using Visual Studio 2017 version 15.4 and Entity Framework Core with the following Nuget Packages installed.
I entered this with my connection string information, but am receiving the following error below.
Code:
PM> Scaffold-DbContext "Host=localhost;Database=mydatabase;Username=myuser;Password=mypassword" Npgsql.EntityFrameworkCore.PostgreSQL
Error:
Configuration system failed to initialize
I found my error. I added the following code to my App.config file, based on help documents I was reading and this code was not needed:
<AutoGenerateBindingRedirects> true </AutoGenerateBindingRedirects>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
</ItemGroup>

EntityFramework 6.1 cannot connect

I have a class library I have been using for over a year that has recently stopped working after upgrading to EF 6.1.
I have tried various methods for passing in the connect string to my Context class constructor but while it seems to correctly pass the string I invariably receive:
'(((System.Data.Entity.DbContext)(context)).Database.Connection).ServerVersion' threw an exception of type 'System.InvalidOperationException'
and the connection state stays closed.
Here is my AppConfig:
<?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.0" />
</startup>
<connectionStrings>
<add name="MyContext" connectionString="Data Source=Server;Initial Catalog=DBName;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
</connectionStrings>
<entityFramework>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
My test class:
using System.Data.Entity;
namespace SVMIC.IMS.Entity.IMSClaim
{
public class Context:DbContext
{
static Context()
{
Database.SetInitializer<Context>(null);
}
public Context():base("MyContext")
{
}
}
}
and my test app:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SVMIC.IMS.Entity.IMSClaim;
namespace TestApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Context context = new Context();
}
}
}
The database server is SQL Server 2008 R2.
I assume it is something simple changed in 6.1 and I am just missing it, but I am totally stumped.
Ok, I have resolved the issue.
In frustration at not being able to fix the issue with 6.1, nothing I did made any difference to the result, and even building and stepping through the EF source accomplished little so I rolled back to EF 5.0 and rebuilt my code.
EF 5 immediately returned an error message identifying an issue in the schema definition, a view added by another developer that referenced system views was confusing my template, I fixed the issue and was back working in a matter of minutes.
The lesson learned here was, EF 6 needs some serious work on its error handling, as just returning a generic exception error left me chasing off in every direction, while the error message from EF 5 pointed me directly at the issue.
Based on the comments what appears to have happened is:
The original EF Upgrade did not work, so you were still running on the old EF
When you made the code change, the rebuild triggered that you would use the New EF
But the New EF dll's are not available, so you get the error.
Check you config: the EF Version is 6.0 not 6.1, also the Public key token is the same as for .net 2.0.
Just for information on this error
I was configuring Repository and Unit of Work Design Pattern with EF 6.1 with a simple test database named as "School"
It had following 3 tables
BookMaster
Library and
Student
I had created their respective Entity classes, Configurations classes, Repository classes and also created DB Sets in Entities class.
After few days I had created one more table whose above mentioned classes and DbSets were not created.
What I found is providing connectionstring name in base() constructor parameter was giving me following error
'(context.Database.Connection).ServerVersion' threw an exception of type >'System.InvalidOperationException' entity framework 6.1
However if I pass complete connection string as a parameter to base() method then it was working.
After some Trial and Error I deleted the 4th table that was created and It worked like a dream. So may be it is necessary to utilize all the tables and create the above mentioned classes and DbSets which may resolve this issue
If you are working local MDF file, the update the folder path of MDF file in App.config/ Web.config
else copy the dbmx App.cofig connectionStrings and paste to your project App.config/Web.config file.