DropCreateDatabaseIfModelChanges when EF is another project - c#

I have separated my solution in separate projects, a DAL project with entity framework and an ASP.NET MVC project.
I want to use DropCreateDatabaseIfModelChanges, but I don't know where to put it to make it work.
I've tried to put it in the web.config of the MVC project and the app.config of the DAL project (both by making use of the context element), I've tried putting it in the global.asax (Database.SetInitializer(new DropCreateDatabaseIfModelChanges<BreakAwayContext>());), I've tried a custom initialization class, but none of these seem to work.
If possible, I don't want to make use of migrations. How can I make it work?

You could create a class to implement CreateDatabaseIfNotExists and call Database.SetInitializer function in Application_Start().
-DbInitializer
public class MyDbInitializer : CreateDatabaseIfNotExists<MyDbContext>
{
protected override void Seed(MyDbContext context)
{
//Data initializing...
}
}
-Application_Start
protected void Application_Start()
{
Database.SetInitializer(new MyDbInitializer());
}
The database will be create when running the application.
And if you would like to do a automatic migration of database, use MigrateDatabaseToLatestVersion class
public class Configuration : DbMigrationsConfiguration<MyDbContext>
{
public Configuration()
{
this.AutomaticMigrationsEnabled = true;
}
}
-Application_Start
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext,Configuration>());
Howerver, I recomand that using migraion commands will be more flexible. See this walkthru: Overview of Entity Framework Code First Migrations with example, by Bhavik Patel.

I guess by 'database initialization' you actually mean 'updating the database schema'.
Set the EfRepository as start up project of the solution
Open the Package manager console Choose EfRepository as default project
Run the following commands:
Enable-Migrations -ConnectionStringName "EfDataRepository"
Add-Migration Initial -ConnectionStringName "EfDataRepository"
Update-Database -ConnectionStringName "EfDataRepository" -Script -SourceMigration:0
This will give you a .sql script. Execute it against your database (and usually store it as part of the solution - either Create.sql or some kind of a migration .sql, depends on whether you already have a schema or you are creating it from scratch).
Of course, replace EfDataRepository with the data connection name from your .config file.

Related

Intercepting SqlServerMigrationsSqlGenerator to prevent migration of certain tables?

I am trying to use EF Core 3.0 migrations with a hybrid of an existing tables and new tables built with code first. To prevent the scaffolding of the existing tables I would like to decorate the model class with an attribute (fluently or annotations) so that the migration code generation for those tables is skipped but the model is still built into the DbContext class.
The approach I'm taking is to add the following lines to OnConfiguring
optionsBuilder.ReplaceService<IMigrationsSqlGenerator, SkipMigrator>();
And then creating a SkipMigrator with the following code
public class SkipMigrator:SqlServerMigrationsSqlGenerator
{
public SkipMigrator(
MigrationsSqlGeneratorDependencies dependencies,
IMigrationsAnnotationProvider migrationsAnnotations)
: base(dependencies, migrationsAnnotations){}
protected override void Generate(
MigrationOperation operation,
IModel model,
MigrationCommandListBuilder builder)
{
if (operation.FindAnnotation("SkipMigrations")!=null)
{
Console.WriteLine("Skipping table:");
}
else
{
base.Generate(operation,model,builder);
}
}
}
I assumed that the Generate method was what triggered the creation of the migration code file but it never gets called. Id there a different place I should be intercepting the code generation?
If there a different/simpler way to tell migrations to skip tables yet still keep them in my DbContext?
Your means of trying to create your own IMigrationsSqlGenerator was correct, and I've used that approach before to alter the SQL that is generated as part of a migration.
services.AddDbContext<MyDbContext>(opt =>
{
opt.UseSqlServer();
opt.ReplaceService<IMigrationsSqlGenerator, SkipMigrator>();
});
However, as of EF Core 5.0 it's now much easier to exclude specific tables from migrations using the ExcludeFromMigrations() method on a TableBuilder:
public class ReportingContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().ToTable(nameof(Users), t => t.ExcludeFromMigrations());
}
}
More info: https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-efcore-5-0-rc1/#exclude-tables-from-migrations
If there a different/simpler way to tell migrations to skip tables yet still keep them in my DbContext?
Yes, but it requires a different approach.
Instead of using your current DbContext class for creating migrations, create a SecondDbContext class only for the very purpose of creating migrations. This new SecondDbContext class will hold the DbSets<T> that you want EF to do its migrations on.
Then simply specify the second context when calling add-migration UpdateTable -c SecondDbContext and then update-database -c SecondDbContext.

How to create Up and Down Methods using migrations?

I am new to Code first, can you tell me how i can have all Up and Down methods for all tables in the database like below(given for one table)
public partial class abc: DbMigration
{
public override void Up()
{
AddColumn("dbo.UserTasks", "ServiceTechReason", c => c.Long());
}
public override void Down()
{
DropColumn("dbo.UserTasks", "ServiceTechReason");
}
}
i want all three types for a table viz .cs , .Designer.cs , .resx.
2) Can you explain the above example, i pick it from somewhere on internet i was searching for this but found nothing. is abc is my table name in database?
Provide me link if it is already answered.
EDIT
As mentioned by #scheien i already tried those commands they do not automatically override up and down methods for a table
Creating migrations is done by running the command Add-Migration AddedServiceTechReason.
This assumes that you have already enabled migrations using the Enable-Migrations command.
To apply the current migration to the database, you'd run the Update-Database. This command will apply all pending migrations.
The point of Code-First migrations is that you make the changes you want to your Entity(ies), and then add a new migration using the Add-Migration command. It will then create a class that inherits DbMigration, with the Up() and Down() methods filled with the changes you have made to your entity/entities.
As per #SteveGreenes comment: It does pick up all changes to your entities, so you don't need to run it once per table/entity.
If you want to customize the generated migration files, look under the section "Customizing Migrations" in the article listed.
All these commands are run in the package manager console.
View -> Other windows -> Package Manager Console.
Here's a great article from blogs.msdn.com that explains it in detail.

Models.ApplicationDbContext for all models in an Asp.Net MVC 5 application?

I've creating an Asp.Net MVC 5 website. I will need to add customized fields in ApplicationUser and associate (add foreign keys) it with other models. I think I should just use one context type. However, the code scaffold already generate the following ApplicationDbContext class. Can I just put all my public DbSet<...> ... { get; set; } in the class? Or is there a better pattern?
namespace MyApp.Models
{
// You can add profile data for the user by adding more properties to your User class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : User
{
}
public class ApplicationDbContext : IdentityDbContextWithCustomUser<ApplicationUser>
{
}
}
There is an excellent video explaining that matter.
Just check the free ASP.NET MVC 5 Fundamentals course by Scott Allen.
The exact answer is here (starts at 3:30).
I would advise keeping them separate. There is really no reason to couple two parts of the system together. To add another DbContext just add a file to models called YourContext.cs.
public class YourContext: DbContext
{
public YourContext() : base("name=YourContext")
{
}
// Add a DbSet for each one of your Entities
public DbSet<Room> Rooms { get; set; }
public DbSet<Meal> Meals { get; set; }
}
Then in the root web.config
<add name="YourContext" connectionString="Data Source=(localdb)\v11.0; Initial Catalog=YourContext; Integrated Security=True"" providerName="System.Data.SqlClient" />
When you run enable-migrations in the package manager console you will be asked which dbcontext you want to migrate. Pick YourContext.
EDIT: No need to add repos / unit of work the Entity Framework does this for you.
Please note: This was written as in beta2 where ALLOT has changed! Hopefully most of it will stick but there are no guarantees until RC.
DO NOT USE NuGET package manger (until RC) as it does NOT pick-up on the .NET 5 packages required and it will install EF 6 and mess up your project. (We are after EF 7)
In the projects.json you need to have the following dependencies. (or beta2 when its out, or the latest on RC)
"EntityFramework": "7.0.0-beta1",
"EntityFramework.Relational": "7.0.0-beta1",
"EntityFramework.Commands": "7.0.0-beta1",
"EntityFramework.Migrations": "7.0.0-beta1",
"EntityFramework.SqlServer": "7.0.0-beta1"
Add a new folder DBContexts and add a c sharp file with your new context stuff.
public class BlaBlaDB : DbContext
{
public DbSet<Models.MyOtherModel> MyOtherModels { get; set; }
protected override void OnConfiguring(DbContextOptions options)
{
options.UseSqlServer();
}
}
and in your config.json make sure to add a connection string, the exact same as the IdentityDB just with you new name. Then in startup.json register your databse.
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<DataContexts.IdentityDB>()
.AddDbContext<DataContexts.BlaBlaDB>();
This has to compile because k will run this project and use the startup to inject your context and then execute everything you need. As of now VS2015 Beta does NOT have all/ or they do not work, the command for EF.
You need to go and install KRE for Windows.
Open command prompt, browse to your project directory, enter the solution and enter the following commands.
k ef context list
k ef migration add -c (context.from.above) initial
k ef migration apply -c (context.from.above)
You now have multi context migration. Just keep on adding context and repeat this as you need it. I used this on localdb, as the default project set-up so that it can work stand alone in any environment, like Linux.
Please Note: You still need to create a Service, containing the Interface and Implementation and then register that in startup.json More information here

Can't make EF Code First work with manually changed data base

I've added two new properties to my domain model class and two properties to a data table accordingly. Then I tried to launch my mvc web application and got
The model backing the 'EFDbContext' context has changed since the database was created.
Consider using Code First Migrations to update the database
(http://go.microsoft.com/fwlink/?LinkId=238269).
Having read the following posts:
MVC3 and Code First Migrations
EF 4.3 Automatic Migrations Walkthrough
I tried to Update-Database through Package Manager Console, but got an error
Get-Package : Не удается найти параметр, соответствующий имени параметра "ProjectName".
C:\Work\MVC\packages\EntityFramework.5.0.0\tools\EntityFramework.psm1:611 знак:40
+ $package = Get-Package -ProjectName <<<< $project.FullName | ?{ $_.Id -eq 'EntityFramework' }
+ CategoryInfo : InvalidArgument: (:) [Get-Package], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,NuGet.PowerShell.Commands.GetPackageCommand
The EntityFramework package is not installed on project 'Domain'.
But the Entityframework is installed on project Domain. I removed it from references, deleted package.config and sucessfully reinstalled EF. But Update-Database still returns same error. Update-Database -Config does as well
What am I doing wrong?
EDIT
Many thanks to Ladislav Mrnka, I'll try to rephrase my question. As far as I changed my data table manually, I am not expected to use migration. But how can I now make EF work with manually edited domain model class and data table?
Try to add this to startup of your application (you can put it to App_Start):
Database.SetInitializer<EFDbContext>(null);
It should turn off all logic related to handling the database from EF. You will now be fully responsible for keeping your database in sync with your model.
I had the same problem and this is how I fixed the issue.
I dropped table __MigrationHistory using sql command and run the update-database -verbose again.
Apparently something was wrong with this automatic created table.
Answer 2 was exactly what was needed. Although when I got to the App_Start I realized that there were 4 configuration files and didn't see where this would fit in any of them. Instead I added it to my EF database context
namespace JobTrack.Concrete
{
public class EFDbContext : DbContext
{
//Set the entity framework database context to the connection name
//in the Webconfig file for our SQL Server data source QSJTDB1
public EFDbContext() : base("name=EFDbConnection")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Remove the tight dependency on the entity framework that
//wants to take control of the database. EF by nature wants
//to drive the database so that the database changes conform
//to the model changes in the application. This will remove the
//control from the EF and leave the changes to the database admin
//side so that it continues to be in sync with the model.
Database.SetInitializer<EFDbContext>(null);
//Remove the default pluaralization of model names
//This will allow us to work with database table names that are singular
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
//Allows for multiple entries of the class State to be used with
//interface objects such as IQueryTables for the State database table
public DbSet<State> State { get; set; }
}
}

EF add-migration exception: could not load assembly

I have only 2 days experience with EF Migrations, so please be kind...
I have a fairly large existing WPF WCF MVVM EF 4.1 solution which needs to be migrated to EF 4.3.1 and begin using Migrations. The solution's "Services" project contains four DbContext's, each in its own namespace, and each associated with its own database.
Before I began modifying the large solution, I did some experimentation with a small sample console app with only a single project and two DbContexts, mostly based on the example provided by "e10"
(EF 4.3 Auto-Migrations with multiple DbContexts in one database). The sample app works well, and I can do add-migration and update-database separately for the two contexts (by specifying the -configuration parameter).
But when I tried to replicate the same approach with the "real" (large) solution - with four DbContexts - I ran into a problem: when I invoke add-migration in PMC and specify any of the four configuration names, add-migrations gets an exception saying it can't load the Services assembly.
Here's what I did with the large solution:
1) Added the EF 4.3.1 NuGet package to my Core, Services and UI projects (this last bit may be important).
2) created a Migrations folder in my Services project and manually created a Configuration.cs file containing four classes which inherit from DbMigrationsConfiguration<type>, where type is App, Catalog, PortfolioManagement or Scheduler. (code is below)
3) added a property to one of the model classes associated with the App DbContext, so there would be something to migrate
4) from the PMC, invoked add-migration:
PM> add-migration App_AddNewProperty -config App
Note that I didn't do "Enable-Migrations" because, as e10 said in his post:
" You dont need to enable migration since you already did with the ... classes above" (referring to the classes in Configurations.cs).
5) add-migration gets exception: Could not load file or assembly 'MyApp.Services' or one of its dependencies
I enabled binding-failure logging, and the failure log shows that it's trying to locate the Services assembly in the UI's bin/debug folder, rather than in the Services project).
And it fails the same way even if I have the Default Project in the PMC set to the Services project (Default Project defaults to the UI project).
I suspect this is caused by the UI not having a reference to the Services assembly (it has a WCF Service Reference, but not an assembly reference). But if this is the problem, how do I force PMC to not start at the UI project? Or can I "unassociate the UI project from the EF package"?
Thanks!
DadCat
Configurations.cs:
namespace MyApp.Services.Migrations
{
internal sealed class App : DbMigrationsConfiguration<Geophysical.Skimmer.Services.App.Repository.ModelContainer>
{
public App()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "MyApp.Services.App.Repository.ModelContainer";
}
protected override void Seed(MyApp.Services.App.Repository.ModelContainer context)
{
... no code here
}
}
internal sealed class Catalog : DbMigrationsConfiguration<Geophysical.Skimmer.Services.Catalog.Repository.ModelContainer>
{
public Catalog()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "MyApp.Catalog.Repository.ModelContainer";
}
protected override void Seed(MyApp.Services.Catalog.Repository.ModelContainer context)
{
... no code here
}
}
internal sealed class PortfolioManagement : DbMigrationsConfiguration<Geophysical.Skimmer.Services.PortfolioManagement.Repository.ModelContainer>
{
public PortfolioManagement()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "MyApp.PortfolioManagement.Repository.ModelContainer";
}
protected override void Seed(MyApp.Services.PortfolioManagement.Repository.ModelContainer context)
{
... no code here
}
}
internal sealed class Scheduler : DbMigrationsConfiguration<Geophysical.Skimmer.Services.Scheduler.Repository.ModelContainer>
{
public Scheduler()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "MyApp.Services.Scheduler.Repository.ModelContainer";
}
protected override void Seed(MyApp.Services.Scheduler.Repository.ModelContainer context)
{
... no code here
}
}
}

Categories