Override "dbo" schema name in EntityFramework Code First Migrations - c#

I'm trying to create an schema independent model with EntityFramework Codefirst and an Oracle database but EF uses as defaults for migrations dbo as schema.
I overridden OnModelCreating method on my DBContext to solve this and use the user in the connectionString instead
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema(string.Empty);
}
The problem is that __MigrationHistory ignores this default schema and I get this error when running first migration:
ORA-01918: User 'dbo' does not exist
Tried this msdn entry to customize the schema for this table.
CustomHistoryContext:
public class CustomHistoryContext : HistoryContext
{
public CustomHistoryContext(DbConnection dbConnection, string defaultSchema)
: base(dbConnection, defaultSchema) {}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema(String.Empty);
}
}
And DBConfiguration:
public sealed class Configuration :
DbMigrationsConfiguration<Model.MyDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
(connection, defaultSchema) => new CustomHistoryContext(connection, defaultSchema));
}
protected override void Seed(Model.Model1 context)
{
}
}
And is working fine for the first migration. But when I modify my entity model and try to reflect this change with add-migration command I get the following error:
Unable to generate an explicit migration because the following
explicit migrations are pending: [201706281804589_initial,
201706281810218_pp2]. Apply the pending explicit migrations before
attempting to generate a new explicit migration.
Looks like EF gets lost and can't find migrations history at this point.
When I comment the SetHistoryContextFactory instruction in Configuration it works for subsequent add-migration commands but this workaround isn't enough for scenarios when I want to run all migrations from scratch like deploying.
Does anyone knows if I'm in the good way to accomplish this or if there is a better workaround for this?

Go to Migrations -> Configuration.cs and below mentioned code. This fix worked for me!
class Configuration : DbMigrationsConfiguration<CodeFirstOracleProject.Context>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
var historyContextFactory = GetHistoryContextFactory("Oracle.ManagedDataAccess.Client");
SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
(dbc, schema) => historyContextFactory.Invoke(dbc, "YourSchemaName"));
}
}

Try runnig Enable-Migrations -force again. Then run Add-Migration SomeDescription –IgnoreChanges. After that, run "Update-Database - Verbose". This worked to me

I successfully tried the following inside the Configuration : DbMigrationsConfiguration class for Oracle, in order to change the history schema to "Test":
var historyContextFactory = GetHistoryContextFactory("Oracle.ManagedDataAccess.Client");
SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
(dbc, schema) => historyContextFactory.Invoke(dbc, "Test"));
So basically, instead of trying to register a custom history context with unchanged default schema, I tried to register the default history context with changed default schema.
The result: when I run Update-Database -Script, the resulting script contains the new schema for creation of the __MigrationHistory table as well as for inserting the new history values:
create table "Test"."__MigrationHistory"
-- ...
insert into "Test"."__MigrationHistory"("MigrationId", "ContextKey", "Model", "ProductVersion") ...
However, lets be perfectly clear: I just tried what I expected to work by intuition and it did work for me. I didn't find any reliable documentation to support this solution.

open Migrations -> Configuration.cs and add
public Configuration()
{
AutomaticMigrationsEnabled = false;
var historyContextFactory = GetHistoryContextFactory("Oracle.ManagedDataAccess.Client");
SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
(dbc, schema) => historyContextFactory.Invoke(dbc, "your_schema_name_hear"));
}

Related

Auto migration in EF Core in three tier application

i have three tier application in Asp.net Mvc Core and use EF core,
now i want create auto migration ,
i have DAL layer that my context available here
public class AdminContext : DbContext
{
public AdminContext(DbContextOptions<AdminContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<AdsAdsCategory>()
.HasKey(bc => new { bc.AdsId, bc.AdsCategoryId });
modelBuilder.Entity<AdsAdsCategory>()
.HasOne(bc => bc.Ads)
.WithMany(b => b.AdsAdsCategories)
.HasForeignKey(bc => bc.AdsId);
modelBuilder.Entity<AdsAdsCategory>()
.HasOne(bc => bc.Category)
.WithMany(c => c.AdsAdsCategories)
.HasForeignKey(bc => bc.AdsCategoryId);
}
public DbSet<Ads> Adses { get; set; }
public DbSet<AdsCategory> AdsCategories { get; set; }
public DbSet<AdsPosition> AdsPositions { get; set; }
public DbSet<AdsCustomer> AdsCustomers { get; set; }
}
and in my application startup
i write this code
var context = app.ApplicationServices.GetService<AdminContext>();
if (!context.Database.EnsureCreated())
context.Database.Migrate();
when i run application database was created and table generate but __migrationhistory doesn't exist and migration not generate,
when in start up i remove this line code
if (!context.Database.EnsureCreated())
database was created and __migrationhistory table generated,but my model table not generate,
how i can solve this problem ?
and run auto migration in EF Core in three tier application?
You need to do the following to enable Migration in MVC .NET Core.
1-open the Package Manager Console in Visual Studio. Type and execute this code.
add-migration ClassName
pm> add-migration FirstInitialize
2-After executing the code, the migration classes will be created for your models
public partial class FirstInitialize : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
//After executing the code, this section will be automatically generated for your models
}
}
3-Then, with the following code you enter in the class section of the program.cs main method, your models will be built into a database.
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<YouDbContext>();
context.Database.Migrate();
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the atabase.");
}
}
4-Each time you change your models or add a new one, you have to repeat the steps. Choose a new name for your migration every time.
Sample:
pm> add-migration SecondInitialize
*I can't speak english well
Automatic migration like in EF6 do not exist in EF core. You either have to generate your migrations before starting and then use
context.Database.Migrate();
or you drop your whole database on each launch and use
context.Database.EnsureCreated();
to recreate the updated database.
The second one wont allow you to add any migrations later on, so you have to recreate entire database each time. To delete database you can use
context.Database.EnsureDeleted();

what is the reason of getting 'Unable to update database error' when giving enable-migrations command

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.

DBContext overwrites previous migration

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";
}
}

Database isn't generated from model

I'm trying to generate a database from a model. I believe I've setup everything I can find in other questions/walktroughs, but my database doesn't seem to be generated.
Context:
public class DatabaseContext : DbContext {
public DatabaseContext()
: base("Name=DatabaseContext") {
}
public DbSet<Show> Shows { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Configurations.Add(new ShowMap());
}
}
Mapping:
public class ShowMap : EntityTypeConfiguration<Show> {
public ShowMap() {
ToTable("Shows");
// Key
// Properties
}
}
Initializer:
public class DatabaseInitializer : DropCreateDatabaseAlways<DatabaseContext> {
private List<Show> _shows = new List<Show>();
protected override void Seed(DatabaseContext context) {
LoadShows();
_shows.ForEach(s => context.Shows.Add(s));
}
private void LoadShows() {
// Creating models
}
}
Global.asax:
Database.SetInitializer(new DatabaseInitializer());
Web.config:
<add name="DatabaseContext" connectionString="Data Source=JEROEN-DESKTOP\SQLEXPRESS;Initial Catalog=NoName;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
I have manually created the schema 'NoName' without adding tables. Executing my program goes without problems, but no table is generated. When I look at the connections in the VS SQL server object explorer I can see both localdb and SQLEXPRESS don't contain any relevant tables.
Another thing to note: I have added EntityFramework to my project using nuget, but when I rightclick on any file/folder, I don't see EntityFramework in the context menu. Could this be the issue? I've removed and added EF to the project, but it's still not showing up. There's an 'EntityFramework' entry in my References folder though.
I would start looking at a few things, permissions being one. Make sure the delegating caller can actually create on this database. Also validate that EF is access the database during debugging : base("name=DatabaseContext"). If you can access the database, IntelliTrace will give you the out put statements it is creating.
Also, I would validate migrations is enabled. Using Nuget Package Manager Console run, Enable-Migrations.The full tutorial is Building an Initial Model & Database

Entity Framework Code-First: Migrate a database known only at runtime

I'm trying to migrate a database that is only known at runtime, which means that I cannot use the Package Manager Console to update the database. Also it's not just one, but many databases, but it is the same schema for all of them :)
I'm using Ninject to generate and inject the connection string on the DbContext object. The context constructor looks just like this:
public class MyEntities : DbContext
{
public MyEntities(string database) : base(database) { }
/* Properties code omitted. */
}
The method to instantiate a context follows:
public MyEntities GetDatabase(string databaseName, string connectionString)
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectionString);
builder.InitialCatalog = databaseName;
MyEntities context = this._kernel.Get<MyEntities>(new ConstructorArgument(
"database", builder.ConnectionString));
Database.SetInitializer<MyEntities>(
new MigrateDatabaseToLatestVersion<MyEntities, MyEntitiesMigrationConfiguration>("MyEntities"));
return context;
}
When a context is retrieved the method creates a connection string and passes it as parameter to the constructor of MyEntities. Also I specify in the method the type of migration I want (in this case MigrateDatabaseToLatestVersion).
The migration code follows:
public partial class MyAccountInMonth : DbMigration
{
public override void Up()
{
AlterColumn("AccountsInMonths", "MovementDebtMonth", c => c.Long(nullable: false));
AlterColumn("AccountsInMonths", "MovementCreditMonth", c => c.Long(nullable: false));
AlterColumn("AccountsInMonths", "BalanceMonth", c => c.Long(nullable: false));
AlterColumn("AccountsInMonths", "MovementDebtAccumulated", c => c.Long(nullable: false));
AlterColumn("AccountsInMonths", "MovementCreditAccumulated", c => c.Long(nullable: false));
AlterColumn("AccountsInMonths", "BalanceAccumulated", c => c.Long(nullable: false));
}
public override void Down() { /* Code omitted */ }
}
When I run the application, the following error occurs:
Cannot find the object "AccountsInMonths" because it does not exist or you do not have permissions.
What the migration does is change the type of the column AccountsInMonths from int to long.
It is a migration error, because the stack trace has calls to it. At this moment I can only think that the problem can be permissions because the table exists. Other possibility is some kind of problem on the connection string. Please, anybody has a clue for this? Thanks in advance!
PS: if it is not clear I can add more information to the question.
I Had the several issue. Here is the solution:
1) Make your Configuration as a public class:
public sealed class Configuration : DbMigrationsConfiguration<YourContextClassHere>
2) Make your Seed() method as a public
2) Add anywhere the code below, this will apply the latest migration and updates your db:
Configuration configuration = new Configuration();
configuration.ContextType = typeof(YourContextClassHere);
var migrator = new DbMigrator(configuration);
// This will update the schema of the DB
migrator.Update();
// This will run Seed() method
configuration.Seed(new YourContextClassHere());
To migrate a database outside of Visual Studio and the Package Manager Console, use the accompanying migrate.exe tool that is located in the EntityFramework nuget package. It basically let you do the same migration from a command line.
You can use the Package Manager Console with Update-Database. It has a switch to specify connection string - either connection string itself ($ConnectionString and $ConnectionProviderName) or named one from config ($ConnectionStringName).
Or you can use DbMigrator class to handle it yourself in code (similar to what's actually migrate.exe doing).

Categories

Resources