Should i avoid multi datacontext and migration configuration on code-first project? - entity-framework

I am working on a ASP.NET MVC 5.1 project, I would using the ASP.NET Identity feature and code first.
By default, the ASP.NET Identity having their own datacontext (IdentityModels.cs) which inherit Microsoft.AspNet.Identity.EntityFramework.IdentityDbContext.
Because i afraid to influence the Identity model.
So i create another context inherrit DbContext , and create another migration configuration by following command:
enable-migrations -ContextTypeName PosApp.Models.OtherContext -MigrationsDirectory:OtherContextMigrations
And using specific configuration command line to update database:
Add-Migration -ConfigurationTypeName
PosApp.OtherContextMigrations.Configuration -Name GenDB Update-Database
-ConfigurationTypeName PosApp.OtherContextMigrations.Configuration
However, i found that it make the migration conflict between tables.
For example:
DataContext A and Configuration A:
Generate Table: Blog , Post , Comment
DataContext B and Configuration B:
Generate Table: User, but reference to Blog (1:N, that mean 1 user can have own multi blogs).
If i type command line - add-migration base on Config B.
The Blog table will be generate again, and conflict because the table exist on Config A.
Even i can override OnModelCreating() event and using modelBuilder.ignore<T> , but it resulting a mess.
So do i avoid multi config of migration?
Or any advantage on it?

You are on the right track using moddelBuilder.ignore. In your identityDbContext add:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<Blog>();
base.OnModelCreating(modelBuilder);
}
Then, to use your relationship from the User to the Blog, create a new data-context inheriting from IdentityDbContext and don't add a migration to it.

Related

Failed initial migration in Entity Framework Core on .NET 6 Isolated [duplicate]

.NET6 EFCore & Cosmos Migration issue. Need some help.
Hello folks. I am new in the world of .Net and I am facing an issue that Google has failed to help me solve. You're kind of my last regard.
So. I am trying to connect to an Azure Cosmos DB from my little HomeControlCenter Project using EFCore 6.0.3
The Error:
Unable to resolve service for type 'Microsoft.EntityFrameworkCore.Migrations.IMigrator'. This is often because no database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext>
object in its constructor and passes it to the base constructor for DbContext.
My Program.cs:
builder.Services.AddDbContext<ControlCenterContext>(options =>
options.UseCosmos(builder.Configuration.GetConnectionString("DefaultConnection"), "ToDoList"));
My DbContext Impl:
public class ControlCenterContext : DbContext
{
public ControlCenterContext(DbContextOptions<ControlCenterContext> options) : base(options)
{
}
}
I also tried to use an override of OnConfiguring instead of the Program.cs line.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseCosmos(
"<AccountEndpoint>",
"<accountKey>",
databaseName: "ToDoList");
Nothing helped. When ever I run dotnet ef migrations add "initialSetup" I get the error mentioned above.
I read the error carefully and as you can see, I did apply all the necessary constructor params & other additions... I even tried to create a vanilla project and do the same all over again...
I couldn't find anything official from Microsoft, but the author of this blog states migrations using EF Core for CosmosDb are not supported: https://www.thereformedprogrammer.net/an-in-depth-study-of-cosmos-db-and-ef-core-3-0-database-provider/#1-no-migrations-can-cause-problems
This makes sense since CosmosDB is a document database, so it has no schema, it's just a bunch of JSON files. I ran into this issue when I wanted to use migrations to make seed data. The only solution I could think of was to create a separate project that uploaded the seed data with static values. But again, this was only seed data and not schema updates.

Entity Framework 6 migrations odd behaviour

I am using EF6 Code First with migrations in a new project. I have used this in a few projects already without issue.
Now this new project is against an existing database.
I generated the standard Initial migration file, then deleted all the contents leaving just the Up() and Down() methods. This has worked for me in other projects, but not this time.
When I run update-database from the Package Manager Console, all works as expected.
PM> update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
No pending explicit migrations.
Running Seed method.
Then I execute the migrations from code (as needed in production) and I get...
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.
I have been trying to get my head around this one for two days, and not getting anywhere.
I have even added another migration file called "stub" and it is generated blank. EF does not see any changes to my model (of which there are none), so it has nothing to generate. Yet the migration execution via code persists with the error that there are migrations pending.
I have attached a logger to the code execution of the migrations and the output is this.
Target database is: 'FMS' (DataSource: (local)\SQL2012, Provider: System.Data.SqlClient, Origin: Configuration).
No pending explicit migrations.
And then I get the error message in my browser.
My configuration class
namespace FMS.Infrastructure.Repository.EF.Migrations.Stage
{
public sealed class StageConfiguration : DbMigrationsConfiguration<StageDb>
{
public StageConfiguration()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = #"Migrations\Stage";
CommandTimeout = 3000;
ContextKey = "FMS.Stage";
}
}
}
And the code that performs the migrations
Database.SetInitializer(new MigrateDatabaseToLatestVersion<StageDb, StageConfiguration>());
var dbMigrator = new DbMigrator(new StageConfiguration());
var logger = new MigratorLoggingDecorator(dbMigrator, new DbMigrationLogger());
foreach (string migration in dbMigrator.GetPendingMigrations())
Console.WriteLine(migration);
logger.Update();
I hope this is clear enough for those willing to try assist. If anyone has a tip, I am all ears. This is making me grey.

Not able to update-database with Code First Entity Framework 6.1

In my project I am using code first and I was able to create my database and apply migrations to it via the nuget package manager console.
Now I added a second database context to my application and this context is not code first. this context is built on an existing database.
after adding the second context ... if I try to do a update-database, I get an error
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
System.NotSupportedException: Creating a DbModelBuilder or writing the EDMX from a DbContext created using Database First or Model First is not supported. EDMX can only be obtained from a Code First DbContext created without using an existing DbCompiledModel.
at System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext context, XmlWriter writer)
at System.Data.Entity.Utilities.DbContextExtensions.<>c__DisplayClass1.<GetModel>b__0(XmlWriter w)
at System.Data.Entity.Utilities.DbContextExtensions.GetModel(Action`1 writeXml)
at System.Data.Entity.Utilities.DbContextExtensions.GetModel(DbContext context)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext, DatabaseExistenceState existenceState)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.GetMigrator()
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
However, I ONLY want to apply migrations to my first context and want the second context to be left alone.
Solved the problem by directly specifying the Configuration type to be updated
update-database -ConfigurationTypeName Company.Project.Migrations.MySpecificConfiguration
This article helped a lot
http://www.dotnet-tricks.com/Tutorial/entityframework/2VOa140214-Entity-Framework-6-Code-First-Migrations-with-Multiple-Data-Contexts.html

Is it possible to get Entity Framework to recognize previous migrations if you change your project namespace?

Let me break down the scenario:
I create my models/mappings using the code-first approach
I setup a database initializer for MigrateDatabaseToLatestVersion
I create a migration using add-migration
This creates a Configuration class like so:
namespace MyApp.Migrations
{
internal sealed class ConfigurationInfo : DbMigrationsConfiguration<MyContext>
{
}
}
I can run my code and the database will be automatically created with no issue.
Now I go in and change the namespace that my Configuration class lives under:
namespace MyApp.Data.Migrations // <-- new namespace
{
internal sealed class ConfigurationInfo : DbMigrationsConfiguration<MyContext>
{
}
}
I drop the database and rerun the code. I now get this message:
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.
When I renamed the namespace that Configuration lived under it no longer recognizes any of the migrations that were previously created.
I did a lot of experimenting and when I set MigrationsNamespace equal to the old value in the Configuration constructor like so:
namespace MyApp.Data.Migrations
{
internal sealed class ConfigurationInfo : DbMigrationsConfiguration<MyContext>
{
public ConfigurationInfo()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "MyApp.Migrations"; // <-- this works
}
}
}
Now everything works, except all of the previously created migrations need to live under the old namespace in order to work, as well as all future ones (which get the old namespace automatically).
This workaround didn't really do what I wanted to do, which is be able to refactor my code and still have entity framework recognize my previous migrations.
What if the name of my project changes, but I have multiple installations out there that are depending on the MigrateDatabaseToLatestVersion database initializer to receive schema changes to my code?
Am I locked into using the same namespace for my DAL as soon as I enable migrations?
This was my own fault, I did the refactor by hand and thought that I had changed the namespace for all files in my project, but I forgot to expand the migration files and update the "designer" files as well!
When I set the same namespace between the configuration file, the migration files, and the migration designer files everything works great, and I can change the namespace at any time without EF losing track of the old migrations.

How to explicitly name the database when using Entity Framework Migrations 4.3

I've recently started using Entity Framework migrations and noticed that the database name is not pulling through for me when I run the Update-Database command.
My connectionstring is:
<connectionStrings>
<add name="DataContext" connectionString="Server=.\SQLEXPRESS;Initial Catalog=TestDB;Trusted_Connection=Yes;" providerName="System.Data.SqlClient" />
</connectionStrings>
The very first time I run Update-Database my database is created with the correct name TestDB. However, as soon as I make a change to one of my entities it will not update any longer for me unless I add a Start Up Project Name (I'm using a multi project solution):
Update-Database -StartUpProjectName "TestDB.Data"
This then makes another new database which migrations will always continue to use. I don't mind having to put in the StartUpProjectName command but is there a way to override the default name for the database this produces? It always creates the database as
TestDB.Data.DataContext
Is there a way to ensure that the database created when passing the StartUpProject name is just called TestDB or is this a limitation of using the StartUpProjectName setting?
As a note, I think the reason I need to specify the StartUpProjectName is that I have a multilayer project setup. The Migrations Configuration file is in my 'Data' project, the entities/models are in my 'Domain' project, etc. I also do not currently have any initialize options in my Global.asax.cs file as I would have used previously on code first ef 4.2. So in my project I just have a DataContext in my Data project and the Migrations Configuration in that project also.
EDIT:
Since I originally setup this question I stumbled onto the 'correct' way to name a database in a multiproject solution. While the answer below will work it does mean you are duplicating your web.config in another area which isn't an ideal solution. Instead you can just put the name into your DbContext by doing something like this (DataContext is just the name I used in my project):
public class DataContext : DbContext
{
public DataContext() : base("DatabaseNameHere")
{ }
public DbSet<Table1> Table1 { get; set; }
public DbSet<Table2> Table2 { get; set; }
public virtual void Commit()
{
base.SaveChanges();
}
}
Thanks,
Rich
You can avoid managing it in app.config by offering it as a parameter:
Update-Database -Verbose
-ConnectionString "CONNECTIONSTRING"
-ConnectionProviderName "System.Data.SqlClient"
-StartupProjectName WEBSITE_PROJECT -ProjectName MIGRATION_PROJECT
Easy-piezy, if you love to type endlessly.
When doing update-database you should specify the project that contains the migrations. Make sure that you have an app.config file in that project that contains the correct connection string.
When splitting up an application over several projects, the connection string used when running the app is the one of the project started. When migrating, the connection string used is the one of the project containing the migrations.
When I did a similar setup I had to add the connection string in two places. A bit awkward, but it works.
You can have your connection string stored in the web.config in your website project and the DBContext and migration files in another project and still share the same connection string. However you need to make sure that as well as setting the Data project (or whatever project has the DBContext etc. in it) as the default project for the Package Manager Console, you ALSO need to make sure that your website is set to the Default StartUp Project!!!
I cannot see this documented anywhere, but a frantic 24 hours of not being able to figure out why my migrations where suddenly being applied to a SQLExpress db, led me to this conclusion.
I tried with Latest EF5 from Nuget.
However Update-Database does not read the App.config from the project that contain the migrations (just like the answer 1 year ago) but it will only read *.config from start up project. It is great but I discover how Add-Migration and Update-Database find a suitable connection string here:
It trying to get "DefaultConnection" connection string first
Then it is trying to get the connection string name based on context class name. E.g. I have the MyContext class derived from DbContext so I can use the "MyContext" connection string name. Useful when I have multiple db connections.
If both the above connection string names are not found, it will fail and show no "DefaultConnection" connection string unless you supply the -ConnectionStringName parameter. See get-help Update-Database to view the help page in the Package Manager Console.
There is no retry or fallback attempt, so if the "DefaultConnection" contains a wrong connection string, it will simply show an error.
If both DefaultConnection and context name exist in the connection strings, DefaultConnection will take precedence.
I would prefer #2 become the first try because the name is more specific but the above steps is what EF5 Migrations do when trying to connect to the db.