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
Related
I am trying to follow the ASP.NET Web Forms tutorial, just with a MySQL connection instead of local: ASP.NET Web Forms - Create the Data Access Layer
I already tested that the connection string works, because I made a dummy table in an existing DB and I can see it in the Server Explorer when I run the app.
But according to the tutorial, it was also supposed to create a DB and tables and seed it. But nothing happens.
This is my connection string:
<add name="myProject" connectionString="Data Source=MY_PC_NAME;User Id=testuser; Password=testpassword; Integrated Security=False" providerName="System.Data.SqlClient"/>
This is the ProjectContext file:
namespace myProject.Models
{
public class ProjectContext : DbContext
{
public ProjectContext() : base("base_name")
{
}
public DbSet<Item> Items { get; set; }
public DbSet<Category> Categories{ get; set; }
}
}
And the ProjectDatabaseInitializer:
public class ProjectDatabaseInitializer : DropCreateDatabaseIfModelChanges<ProjectContext>
{
protected override void Seed(ProjectContext context)
{
GetItems().ForEach(i => context.Items.Add(i));
GetCategories().ForEach(c => context.Categories.Add(c));
}
// some seeding lists below
I then added the initializer to the Global.asax.cs:
Database.SetInitializer(new ProjectDatabaseInitializer());
And both Items and Categories have their corresponding Item and Category models.
But when I run the app, the Server Explorer remains empty.
Note that I modified the original code of the tutorial a bit
MVC Identity Entity Framework model seems to be broken, preventing model updates. It appears that entity framework models created using IdentityDbContext cannot be updated.
I am using MVC Identity and EF, with a production database as well as a development database. The setup is standard - a project - Models, with the EF configuration, DbSets and EF classes. To create the dev database, I have a simple program listed below. I have used this basic configuration without any issues for a long time. But after moving to MVC Identity, I am now unable to update the dev database by adding new classes to my model. Replacing the reference to IdentityDbContext with the plain DbContext removes the errors. Wonder what I am doing wrong.
Not sure if this is relevant, but many of the entities in the model inherit from a BaseEF class to include common fields.
Models and createDb both use EF 6.0.0.0:
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework,
Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
I get the following errors:
(1) If I delete the dev database, and run the createDb program, I get the error, "There is already an object named activities in the database".
(2) If I allow the program to delete the database, I get the error that the model backing the database has changed.
I have tried adding and deleting migrations in the Models project without any success.
I am creating the dev database using the following program:
namespace AzureV1_CreateTestDB
{
class Program
{
static void Main(string[] args)
{
createDb(true);
}
public static void createDb(bool deleteDatabase)
{
IdentityEFContext dbContext = new IdentityEFContext();
if (System.Configuration.ConfigurationManager.ConnectionStrings["IdentityEFContext"].ConnectionString.Contains("EFUpdatetest1"))
{
if (dbContext.Database.Exists())
{
if (deleteDatabase)
{
// The following line throws this error:
// System.InvalidOperationException: 'The model backing the 'IdentityEFContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).'
dbContext.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction
, string.Format("ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE", dbContext.Database.Connection.Database));
dbContext.Database.Delete();
}
}
initDBContext(dbContext);
System.Data.Entity.Core.Objects.ObjectContext oContext = ((IObjectContextAdapter)dbContext).ObjectContext;
if (System.Configuration.ConfigurationManager.ConnectionStrings["IdentityEFContext"].ConnectionString.Contains("EFUpdatetest1"))
{
ExecuteSql(oContext, "ALTER DATABASE EFUpdatetest1 SET ALLOW_SNAPSHOT_ISOLATION ON");
ExecuteSql(oContext, "ALTER DATABASE EFUpdatetest1 SET READ_COMMITTED_SNAPSHOT ON");
}
// insert data
InsertData(dbContext);
closeDBContext(dbContext);
MessageBox.Show("Database successfully created");
}
}
public static void initDBContext(IdentityEFContext dbContext)
{
// The following line throws the error:
// System.Data.SqlClient.SqlException: 'There is already an object named 'Activities' in the database.'
while (((IObjectContextAdapter)dbContext).ObjectContext.Connection.State.ToString() != "Open")
{
((IObjectContextAdapter)dbContext).ObjectContext.Connection.Open();
}
}
}
}
// connectionString in createDb
<connectionStrings>
<add name="IdentityEFContext"
providerName="System.Data.SqlClient"
connectionString="Server=localhost; Integrated Security=False; Database=EFUpdatetest1; User Id=dbtest; Password=Hello.123" />
</connectionStrings>
The EF configuration information is below:
// EntityContext.cs
using Microsoft.AspNet.Identity.EntityFramework;
using Models;
using System.Data.Entity;
using System.Data.Entity.Migrations;
namespace DataAccess
{
//public class IdentityEFContext : DbContext /* this works */
public class IdentityEFContext : IdentityDbContext<User>
{
public IdentityEFContext() : base("IdentityEFContext") { }
static IdentityEFContext()
{
Database.SetInitializer<IdentityEFContext>(new IdentityEFInit());
}
public static IdentityEFContext Create()
{
return new IdentityEFContext();
}
public DbSet<Activity> Activities { get; set; }
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new ActivityConfig());
...
}
}
//public class IdentityEFInit : DropCreateDatabaseIfModelChanges<IdentityEFContext>
public class IdentityEFInit : CreateDatabaseIfNotExists<IdentityEFContext>
{
protected override void Seed(IdentityEFContext context)
{
PerformInitialSetup(context);
base.Seed(context);
}
public void PerformInitialSetup(IdentityEFContext context)
{
// initial configuration will go here
}
}
}
// Entity configurations are as:
namespace DataAccess
{
public class BaseEfConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
where TEntity : BaseEF
{
public BaseEfConfiguration()
{
Property(b => b.ServerVersion).IsOptional();
...
}
}
public class ActivityConfig : BaseEfConfiguration<Activity>
{
public ActivityConfig()
: base()
{
ToTable("Activities");
Property(a => a.Name).IsRequired();
HasRequired(a => a.CreatedBy).WithMany(u => u.ActivitiesCreated).WillCascadeOnDelete(false);
...
}
}
}
// connectionstring in app.config
<connectionStrings>
<add name="IdentityEFContext"
providerName="System.Data.SqlClient"
connectionString="Server=localhost; Integrated Security=False; Database=EFUpdateTest1_Azure; User Id=dbtest; Password=Hello.123" />
</connectionStrings>
The User class is:
public class User : IdentityUser
{
public string Alias { get; set; }
...
}
I had not added the migration after making the change to the model and before creating the test database. I did not realize that if the project containing the entity model has migrations enabled, then the project which uses the model to create the database will use the existing migrations information to create the database, not the EntityTypeConfiguration information.
The solution was to first add a migration after updating the model. Then attempt to create the test database as usual.
Hope this is useful to someone.
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"));
}
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 am developing an application with WPF and Entity Framework CodeFirst.
One requirement is that the user could create separate database file per new project.
DbContext :
public class TestContext : DbContext, IUnitOfWork
{
public TestContext()
: base("TestContext")
{
}
#region Implementation of IUnitOfWork
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
#endregion Implementation of IUnitOfWork
public DbSet<Destination> Destinations { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new DestinationMap());
}
Connection string defined in app config :
<connectionStrings>
<clear />
<add name="TestContext" providerName="System.Data.SqlClient" connectionString="Server=.\sqlexpress;Database=databaseName;Integrated Security=True;Connect Timeout=300;MultipleActiveResultSets=true;" />
</connectionStrings>
I've used StructureMap to inject DbContext in IUnitOfWork interface to implement context per request pattern.
This is StructureMap config :
ObjectFactory.Initialize(x => x.Scan(scanner =>
{
x.For<IUnitOfWork>().CacheBy(InstanceScope.Hybrid).Use<SpitfireContext>();
}));
When user creates new project I try to change connection string and force application create database for new project.
public static void ChangeDatabase(Guid guid)
{
var sqlConnectionStringBuilder =
new SqlConnectionStringBuilder(ConfigHelper.ActiveConnection);
sqlConnectionStringBuilder["Database"] = guid.ToString();
ConfigHelper.ActiveConnection = sqlConnectionStringBuilder.ToString();
Database.DefaultConnectionFactory =
new System.Data.Entity.Infrastructure.SqlConnectionFactory(ConfigHelper.ActiveConnectionString());
Database.SetInitializer(
new MigrateDatabaseToLatestVersion<TestContext, MigrationConfiguration>());
using (var context = new TestContext())
{
context.Database.Initialize(true);
}
}
Application just creates database for first project and after that it tries migrate previews database.
I don't create DbConext object directly in my codes so I can't pass connection string to its constructor.
What do you suggest for my problem ?
What's wrong with my code ?
That's a tricky part - changing connection strings. It kind of works but has issues.
We had a lengthy discussion on that yesterday. Take a look at this (and related) post of mine - which describes some background of troubles for code based on similar approach.
I'd like to help you further if needed - but I'd need some more info...
Why do you say I don't create DbConext object directly in my codes so I can't pass connection string to its constructor ? You have the TestContext - why not pass it through there?
Also I'm not sure about setting the DefaultConnectionFactory, I'll recheck that. It's allowed to be set but it seems recommended on app startup only, not sure. Look up this link in the meantime (it's for EF6 but code is I think similar - and you can look up the source code) - http://msdn.microsoft.com/en-US/data/jj680699
We came to the conclusion that using the DbContext factory was beneficial in such cases.
Would adding a static property on your DbContext class to store the name of the database (Initial Catalog) and then changing the connecting string so that you insert the database name with string.Format work?
Then you could change the database name at any time the next time a context is made it'll be pointing to a new target.