I created a WCF / EF code first service. I created a folder called "Models" and there created my /POCOs. In there I created my context. Now in the Package Manager Console I run enable-migrations. This returns Success and adds the Migrations folder and /Configuration.cs. Now the problem shows itself.
The auto-generated code in Configuration.cs looks like this;
internal sealed class Configuration :
DbMigrationsConfiguration<MyService.**Models**.MyContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
}
protected override void Seed(MyService.**Models**.MyContext context)
Now under the word Models I get the red squiggle and the error message
The type name Models does not exist in the type MyService.MyService.
I have tried everything including renaming the Namespace and the folder. Anywhere the myContext file is placed will cause this error.
I've tried deleting all existence of the Entity Framework and starting over many times but still can't figure this one out! :/
namespace MyService.Models>
{
public class MyContext : DbContext
{
public DbSet<Chain> Chains { get; set; }
public DbSet<Shop> Shops { get; set; }
}
}
Related
I have an ASP.NET MVC application EducationalCenter with the following structure of projects:
DbContext file is EducationalCenterContext.cs in the Data project and looks as follows:
public sealed class EducationalCenterContext: DbContext
{
public DbSet<Student> Students { get; set; }
public EducationalCenterContext( DbContextOptions<EducationalCenterContext> options)
: base(options)
{
Database.EnsureCreated();
}
}
And in Startup.cs file, the dbContext configured as follows in ConfigureService():
services.AddDbContext<EducationalCenterContext>
(options => options.UseSqlServer("Server=localhost;Database=EducationalCenterDb;Trusted_Connection=True;MultipleActiveResultSets=true"));
This is my working version to which I came by fixing errors when try to add-migration. However it seems awful to me that my web app has project reference to the Data project.
What was my first idea:
In appsettings.json I created this section :
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=EducationalCenterDb;Trusted_Connection=True;MultipleActiveResultSets=true"
}
Then I created AppSettings class in the Common project:
public class AppSettings
{
public string ConnectionString { get; set; }
}
Then I try to pass ConnectionString in DAL via DI:
services.Configure<AppSettings>(Configuration.GetSection("ConnectionStrings"));
And created EducationalDbContext.cs:
public sealed class EducationalCenterContext: DbContext
{
private readonly string _connectionString;
public DbSet<Student> Students { get; set; }
public EducationalCenterContext( IOptions<AppSettings>, DbContextOptions<EducationalCenterContext> options)
: base(options)
{
_connectionString = app.Value.ConnectionString;
Database.EnsureCreated();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connectionString);
}
}
But when I try to add-migration via PM Console, I ran into this error:
Could not load assembly 'EducationalCenter.Data'. Ensure it is referenced by the startup project 'EducationalCenter'
Then I added project reference and ran into the next error:
Unable to create an object of type 'EducationalCenterContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
Then I added services.AddDbContext<> in Startup.cs and came to the working version which I mentioned above.
So...
Is it normal that my web app has reference to the data access project?
Is it possible to configure EF in the Data project and ensure normal separation between DAL, BLL and web app?
Putting the context and configuration in a separate project is fine.
You got the first error because "Education Center" was set as start up project but did not have reference to data project.
The second error is because the migration builder needs some connection information in the data project to resolve the connection (to compare EF state and database state) to determine what changes are needed.
First add reference in your data project to:
Microsoft.EntityFrameworkCore.Design
Then add a context factory in your data project that migration console command will discover:
internal class MyContextFactory : IDesignTimeDbContextFactory<MyContext>
{
public MyContext CreateDbContext(string[] args)
{
var dbContextBuilder = new DbContextOptionsBuilder<MyContext>();
var connString = "myconnection string";
dbContextBuilder.UseSqlServer(connString);
return new MyContext(dbContextBuilder.Options);
}
}
I have the following problem with the .NET Core and Entity Framework.
I created myself the .NET Core project, I added DbContext and all the rest. My problem is that I can download the data without the slightest problem, unfortunately I can not save them, i.e. I have the Add method, but I do not have the SaveChanges method.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using CRM.Model.Entities;
namespace CRM.Model.Concrete
{
public abstract class ApplicationContext : IdentityDbContext<ApplicationUser>
{
public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options)
{
}
public DbSet<Category> Categories { get; set; }
public DbSet<Subcategory> Subcategories { get; set; }
public DbSet<SubcategoryL2> SubcategoriesL2 { get; set; }
public DbSet<Event> Events { get; set; }
public DbSet<ApplicationUser> Users { get; set; }
public DbSet<Coupon> Coupons { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<SubcategoryL2>().ToTable("Subs");
#region "Seed Data"
builder.Entity<IdentityRole>().HasData(
new { Id = "1", Name = "Admin", NormalizedName = "ADMIN" },
new { Id = "2", Name = "User", NormalizedName = "USER" }
);
#endregion
}
}
}
ICouponRepository
using System.Threading.Tasks;
using CRM.Model.Concrete;
namespace CRM.Repository.Abstract
{
public interface ICouponRepository
{
Task AddCoupon(Coupon coupon);
}
}
CouponRepository
using System.Threading.Tasks;
using CRM.Model.Concrete;
using CRM.Repository.Abstract;
namespace CRM.Repository.Concrete
{
public class CouponRepository : ICouponRepository
{
private readonly ApplicationContext _applicationContext;
public CouponRepository(ApplicationContext applicationContext)
{
_applicationContext = applicationContext;
}
public async Task AddCoupon(Coupon coupon)
{
await _applicationContext.Coupons.AddAsync(coupon);
await _applicationContext.SaveChangesAsync();
}
}
}
And the problem is here in CouponRepository, i.e.
I have no idea how I can fix it and why it does not work :(
CS1061 The "ApplicationContext" element does not contain the
definition of "SaveChangesAsync" and the available "SaveChangesAsync"
extension method was not found, which takes the first argument of the
"ApplicationContext" type (does not the using directive or the kit
reference?).
Second error
CS0012 C # The "IdentityDbContext <>" type is defined in an
unreferenced set. You must add a reference to the set
"Microsoft.AspNetCore.Identity.EntityFrameworkCore, Version = 2.2.0.0,
Culture = neutral, PublicKeyToken = adb9793829ddae60"
My project is divided into several smaller ones, that is, the main CRM project. In it there are several smaller ones:
CRM.Core
CRM.Services
CRM.Repository
CRM.Resources
CRM.Model
The problem is that without the slightest problem I use the ApplicationContext to retrieve data from the database, unfortunately I can not save any data with it, because the error pops up like in the picture.
when i change
public abstract class ApplicationContext :
IdentityDbContext
to
public abstract class ApplicationContext : DbContext
then all is Ok, but then Identity will not work for me
Solution:
The solution to my problem was to install the Microsoft.AspNetCore.Identity.EntityFrameworkCore package through the NuGet Package.
First of all you need to be calling SaveChangesAsync against the context, not the DbSet, so you should be writing this:
await _applicationContext.SaveChangesAsync();
Secondly, as a bonus, you shouldn't be using AddAsync unless you really need to, you should be doing this:
_applicationContext.Coupons.Add(coupon);
The docs state:
This method is async only to allow special value generators, such as the one used by 'Microsoft.EntityFrameworkCore.Metadata.SqlServerValueGenerationStrategy.SequenceHiLo', to access the database asynchronously. For all other cases the non async method should be used.
From the second error message it is clear what you have to do. Install Microsoft.AspNetCore.Identity.EntityFrameworkCore nuget package to the project where CouponRepository is located as follows:
PM> Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore -Version 2.2.0
Or you can also add Microsoft.AspNetCore.App meta-package to your CouponRepository project by adding the following item.
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
The error should go away now!
I use EF 6 and code first in a project
I try to understand using 'enable-migrations' command.
DbContext and Initializer examples are in simplest form like below .
When I give the command 'enable-migrations' package-manager console outputs an error like below :
Unable to update database to match the current model because there are pending changes and automatic migration is disabled. Either write the pending model changes to a code-based migration or enable automatic migration. Set DbMigrationsConfiguration.AutomaticMigrationsEnabled to true to enable automatic migration.
But If I do not call InitializeDatabase();method from MyDbContext constructor no error occures and no data imports or seed method does not run.
Only database creates.
I want to learn what's the reason and what's the mean of this error If I use InitializeDatabase() method.
Thank you
public class MyDbContext : DbContext
{
public MyDbContext():base("TestDb")
{
Database.SetInitializer(new DbContextInitializer());
InitializeDatabase();
}
protected virtual void InitializeDatabase()
{
if (!Database.Exists())
{
Database.Initialize(true);
}
}
public DbSet<TestModel> TestModels { get; set; }
}
public class DbContextInitializer : CreateDatabaseIfNotExists<MyDbContext>
{
protected override void Seed(MyDbContext context)
{
base.Seed(context);
context.TestModels.Add(new TestModel() {
Name = "Lorem",
Surname = "Ipsum"
});
}
}
Your initializer is inheriting from CreateDatabaseIfNotExists which is not a logical choice for migrations. You have some pending model changes that are not being applied because the model has changed and your initializer is only going to run when the database does not exist.
You could delete your database so it reinitializes with the changes, or switch your initializer to MigrateDatabaseToLatestVersion. Here is a good article on initializers and seeding.
I currently have two DbContexts, ApplicationDbContext and CompanyDBContext. However the problem is that when I run my MVC web application only the CompanyDBContext gets reflected on the database and I see none of the implementation made in ApplicationDbContext being shown in the database. Both my contexts use the same connection string. The ApplicationDbContext was auto-generated when I created my MVC application as I had selected Individual accounts
Currently the ApplicationDbContext looks like this
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DevConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<CompanyDetails>();
}
}
and here is my CompanyDbContext
public class CompanyDBContext : DbContext
{
public CompanyDBContext() : base("DevConnection")
{
}
public DbSet<CompanyDetails> companies { get; set; }
}
I would delete the migrations you have now if you dont need them then use the command below to enable them separately by specifying their names and directories, so they are created separately.
enable-migrations -ContextTypeName MyCoolContext -MigrationsDirectory MyCoolMigrations
http://www.mortenanderson.net/code-first-migrations-for-entity-framework
I was curious, so I looked around, and it seems like the solution for migrations and multiple DbContexts is to have a single DbContext that serves as a complete representation of the database through which initialization and migration is handled, and disable database initialization in the constructor of all other DbContext classes.
You could do this through a combination of Database.SetInitializer and an explicit call to DbContext.Database.Initialize()
Sources
Entity Framework: One Database, Multiple DbContexts. Is this a bad idea?
Shrink EF Models with DDD Bounded Contexts
It's seems like only one dbContext can be updated at a moment. You must Enable-Migration , Add-Migration and Update-Database for each dbContext. This is the way i do it. But my dbContext were in different projects, so may be it can be the same for you! Update separately didn't overwrite my database. It works for me !
In think the problem you have, it that your database tables / migrations are not separated.
In EF6 if you work with more than one context, I recommend to specify the name for the default schema in the OnModelCreating method of you DbContext derived class (where the Fluent-API configuration is).
public partial class ApplicationDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Application");
// Fluent API configuration
}
}
public partial class CompanyDBContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Company");
// Fluent API configuration
}
}
This example will use "Application" and "Company" as prefixes for your database tables (instead of "dbo") in your (single) database.
More importantly it will also prefix the __MigrationHistory table(s), e.g. Application.__MigrationHistory and Company.__MigrationHistory.
So you can have more than one __MigrationHistory table in a single database, one for each context.
So the changes you make for one context will not mess with the other.
When adding the migration, specify the fully qualified name of your configuration class (derived from DbMigrationsConfiguration) as parameter in the add-migration command:
add-migration NAME_OF_MIGRATION -ConfigurationTypeName FULLY_QUALIFIED_NAME_OF_CONFIGURATION_CLASS
e.g.
add-migration NAME_OF_MIGRATION -ConfigurationTypeName ApplicationConfiguration
if ApplicationConfiguration is the name of your configuration class.
In such a scenario you might also want to work with different "Migration" folders in you project. You can set up your DbMigrationsConfiguration derived class accordingly using the MigrationsDirectory property:
internal sealed class ApplicationConfiguration: DbMigrationsConfiguration<ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = #"Migrations\Application";
}
}
internal sealed class CompanyConfiguration : DbMigrationsConfiguration<CompanyDBContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = #"Migrations\Company";
}
}
I want to migrate stored procedures and views in my DB. Since I always migrate to the latest version, a source-control-friendly approach is to drop/recreate all procedures/views during migration process (with this approach there is one file per procedure, instead of one-per-version).
Since old procedures/functions/views might not be compatible with new schema changes, I want to do drop before all migrations, then do the create after all.
Previously I used a customized FluentMigrator, but now I am researching Entity Framework Code First Migrations. I see that I can use Seed to always run code after all migrations.
Is there something I can use to always run code before all migrations?
If you want some code to run before migrations kick in, you can specify a custom database initializer:
public class AwesomeEntity
{
public int Id { get; set; }
}
public class AwesomeDbContext : DbContext
{
static AwesomeDbContext()
{
Database.SetInitializer(new AwesomeDatabaseInitializer());
}
public IDbSet<AwesomeEntity> Entities { get; set; }
}
public class AwesomeDatabaseInitializer : MigrateDatabaseToLatestVersion<AwesomeDbContext, AwesomeMigrationsConfiguration>
{
public override void InitializeDatabase(AwesomeDbContext context)
{
// TODO: Run code before migration here...
base.InitializeDatabase(context);
}
}
public class AwesomeMigrationsConfiguration : DbMigrationsConfiguration<AwesomeDbContext>
{
public AwesomeMigrationsConfiguration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(AwesomeDbContext context)
{
// TODO: Seed database here...
}
}
This sets the custom initializer to a custom AwesomeDatabaseInitializer, which inherits from MigrateDatabaseToLatestVersion. If you want to drop and rebuild the database every time, you should use the DropCreateDatabaseAlways as base class instead, though I'm not sure this lets you run migrations.
In the initializer, you can override the InitializeDatabase method, where you can run code before you call base.InitializeDatabase, which will trigger the database initialization and in turn the Seed method of the migration configuration, AwesomeMigrationsConfiguration.
This is using EF6. I'm not sure if there is an equivalent in earlier versions of entity framework.
I have a solution that is pretty horrible, but works for migrate.exe.
Here is the idea:
Use Seed for AfterAll, as suggested by #khellang.
For BeforeAll, register a custom IDbConnectionInterceptor in MigrationsConfiguration constuctor to capture first connection after the MigrationsConfiguration has been created, then make it unregister itself. Obviously this is absolutely not thread-safe and only OK in application startup or migrate.exe.
Example code:
public class DbMigrationsInterceptingConfiguration<TContext> : DbMigrationsConfiguration<TContext>
where TContext : DbContext
{
public DbMigrationsInterceptingConfiguration() {
BeforeFirstConnectionInterceptor.InterceptNext();
}
protected override void Seed(TContext context) {
Console.WriteLine("After All!");
}
}
internal class BeforeFirstConnectionInterceptor : IDbConnectionInterceptor {
public static void InterceptNext() {
DbInterception.Add(new BeforeFirstConnectionInterceptor());
}
public void Opened(DbConnection connection, DbConnectionInterceptionContext interceptionContext) {
// NOT thread safe
Console.WriteLine("Before All!");
DbInterception.Remove(this);
}
// ... empty implementation of other methods in IDbConnectionInterceptor
}
I am not sure I would be actually using it though.