I have an MVC web application with code-first Entity Framework. We install this application in various computers as a local application. I made a migration to upgrade the database (in this case I added a new table), and after running the migration on upgrade, I want to insert initial data to the database so the users will be able to add/edit/delete them but I don't want the table to be empty at the first time.
Is there a way to do it automatically on upgrade without running a SQL script manually?
Migration class has up method,you can override it and insert/update records using SQL :
public override void Up() {
AddColumn("dbo.Posts", "Abstract", c => c.String());
Sql("UPDATE dbo.Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL");
}
(Source)
Yes there is. You essentially write a class to conditionally check and insert values, and then you link this class to your entity framework database initialiser. It runs each time there is a migration to be performed, but I think you can change exactly when it runs (e.g. Application startup).
This link will give you the rough idea:
Entity Framework Inserting Initial Data On Rebuild
I have an exact code sample on my PC but I won't be on it until tomorrow. If this link doesn't quite do what you want, I can send you some code tomorrow which definitely will.
Related
I'm wondering if this is even possible. I'm writing an app in MVC using ASP.NET Core and EF Core. For the most part I've been doing code-first migrations (that's all I know how to do, as yet) for my entities.
Someone added a table to the database I'm using, and rather than deleting their table and doing it the code-first way, I'd like to just bring their table over using a DB first migration.
Is that even possible to mix and match DB-first/code-first techniques?
If it is, how do I do it? I can't seem to find anything about bringing over just one table. Only migrating a whole database, which is not what I want.
Yes, it's possible. The steps are the following:
Right click on your Models folder.
Select Add -> Add new Item
In the Add New Item Window, select Data -> ADO.NET Entity Data Model. (This would create a new DbContext, but we going to merge the two DbContext) Click Add
In the Entity Data Model Wizard select Code First from database.
Select your connection String.
Click in no, exclude sensitive data...
Uncheck Save connection settings.
Click next
Select the new Table
Click finish
In this point VS would generate two files: a new DbContext and the model for the table.
Now open de new DbContext cut the DbSet of your model and paste in your original DBContext, too cut the content of the OnModelCreating method and paste at the end of the OnModelCreating method of your Original DbContext.
The final step is add a new Migration ignoring the changes.
For example:
Add-migration NewTableAdded -IgnoreChanges -verbose
I am adding Code First migrations to an existing Entity Framework 6 domain with existing databases. I need the following behaviour:
If the database exists, insert the InitialCreate migration but do not perform the contents of the migration Up().
If the database does not exist, create it and run the contents of Up() and Down() to create an empty but correct-schema database.
I need (1) for when I release through the Continuous Delivery deployment. I need (2) for when a developer is cleaning down their machine and starting fresh. I do not want to use automatic migrations.
I appreciate that a Migration has no concept of the Database Context, it's only responsible for generating a series of SQL instructions.
Are these my only options?
1. Move contents of Up and Down out of InitialCreate and into Configuration.Seed
The InitialCreate migration runs Up() but no changes are made. In Seed() we have access to DbContext, so we can work out if the tables exist and create them if needed.
I think this might break when there are lots of migrations to run as Seed() is called after the migrations. On an empty database, the creation of the tables would be happening after updates to those schemas.
2. Perform the Up() method as a SQL Script
Migrations allows the developer to put inline SQL into Up() and Down(). Move the creation of the database into inline SQL and add a IF NOT EXISTS at the top.
I don't like this because you lose the use of the model that is supplied with the InitialCreate. If the model is updated, the fixed SQL string won't.
3. Empty out the Up() and Down() methods, do a release, put the creation code back in, do another release
When the InitialCreate migration is run first time, it won't have anything in it. The entry will go into the migrations database without running anything.
Once that first release has been performed, I can then put the creation code back in so that when future developers run it without a database, it will create properly.
Note: This one is my current favourite as it uses Entity Framework as designed and I can personally control adding the code back in after a release.
Is there a better way?
Edit
I am unable to build the database from empty, this might be something to do with the Context model creation. It uses a bespoke pluggable method:
public MyObjectContext()
{
((IObjectContextAdapter) this).ObjectContext.ContextOptions.LazyLoadingEnabled = true;
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 180;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
System.Type configType = typeof(AnswerMap); //any of your configuration classes here
var typesToRegister = Assembly.GetAssembly(configType).GetTypes()
.Where(type => !String.IsNullOrEmpty(type.Namespace))
.Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
foreach (var type in typesToRegister)
{
dynamic configurationInstance = Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
base.OnModelCreating(modelBuilder);
}
All the map objects are in the same DLL, the domain entities used for the database tables are in a separate DLL.
This is what we do:
1) Create an initial migration that is a snapshot of the current database. Use -IgnoreChanges to keep any code out of the Up(). You don't need the Up() code because EF will compare the prior model (blank) to the one stored in the migration and realize you need to add all the existing objects at the time of the snapshot.
add-migration Initial -IgnoreChanges
2) Add new migrations as you develop. In a team environment you could run into the issues outlined here: https://msdn.microsoft.com/en-US/data/dn481501
3) You can generate an idempotent script that will rebuild an entire system from scratch and apply any (or all) migrations.
Update-Database -Script -SourceMigration $InitialDatabase
https://msdn.microsoft.com/en-us/data/jj591621.aspx?f=255&MSPPError=-2147217396#idempotent
Given Scenratio:
We've built a web application using Asp.net MVC and Entity Framework Code First, which builds a database dynamically for each customer.
Given a connection string (connectionStr) and a certain Configuration, We've made Add Migrations [Name] in order to create an empty migration, which has an empty Up function. We did that on purpose.
We don't wanna use automatic migrations here - we want full control, so we have a program making the migrations using a DbMigrator Class.
Our goal is to run a manual Seed inside this Up function.
This is some of the code incharge of making the migration, which indeed works perfectly:
Dim myConfiguration As New SomeNamespace.Migrations.Config1.Configuration
myConfiguration.TargetDatabase = New Infrastructure.DbConnectionInfo(connectionStr, "System.Data.SqlClient")
Dim dbMig As New Entity.Migrations.DbMigrator(myConfiguration)
If dbMig.GetPendingMigrations.Count > 0 Then
dbMig.Update() ' This makes the Up function work - the problem is inside it.
End If
Problem:
The problem is that when the Up function of the Migration is run, we cannot get the database context. We need it in order to make a Seed.
We hope that there's a way to get the Configuration object (myConfiguration) used to initiate the DbMigration (dbMig) instance, or some other way, so we can get the database context (maybe getting the ConnectionString somehow).
Help getting access to one of configuration object / database context / ConnectionString - would be very appreciated.
I don't think so, because what Up method does is filling Operations collection, and DbMigrator class actually executes these operations. So there is no 'context' when up is called.
What you can do is get connection string via ConfigurationManager class directly
I didn't know quite how to word this. I have an ASP.NET MVC 3 web application with a pretty standard EF 4.1 code first with existing database (non-auto-generated) repository pattern. There's a context which is under a dataservice the web app talks to.
The problem I have is this: say I have a database table with an integer column. The value is 10. If I go into the database itself and enter 25 into the table, no matter how many times I hit refresh on the browser, close the browser and reopen it, clear the browser history, etc, it still persists the value of 10. I have to republish the site.
Why does it do this? Am I blaming the right thing here? Is this an EF problem? an ASP.NET problem? Server problem? ... I don't know where to look into this.
Yes, I've struck this problem in my own applications.
The "entities" (object instances) tracked by Entity Framework are cached in memory, and aren't updated when you requery the database, in case overwriting them would clobber any changes you've made to the cached version.
You can get around it by forcing EF to overwrite existing values, but be aware that this will overwrite anything you've changed, so only do it if you know you've saved any pending changes first.
I've written this extension method to do the job:
public static class DbSetExtensions
{
public static System.Data.Objects.ObjectSet<T> Uncached<T>(this IObjectContextAdapter context)
where T : class
{
var set = context.ObjectContext.CreateObjectSet<T>();
set.MergeOption = System.Data.Objects.MergeOption.OverwriteChanges;
return set;
}
}
So using that, I can say:
var orders = myDbContext.Uncached<Order>().Where(...);
... and the orders set will contain orders that are fresh from the database, overwriting the properties of any Order objects previously queried.
With CTP4, I used to be able to do the following (as suggested by ptrandem):
modelBuilder.IncludeMetadataInDatabase = false
With this line of code, EF doesn't create the EdmMetadata table in my database, and doesn't track model changes.
I was unable to find a way to accomplish this in the new CTP5, so now every time I change my model, I get this:
The model backing the 'MyContext'
context has changed since the database
was created. Either manually
delete/update the database, or call
Database.SetInitializer with an
IDatabaseInitializer instance. For
example, the
DropCreateDatabaseIfModelChanges
strategy will automatically delete and
recreate the database, and optionally
seed it with new data.
So, does everybody know where is the IncludeMetadataInDatabase property in CTP5? Thanks.
CTP5 includes a very cool feature called Pluggable Conventions that can be used to Add/Remove conventions. IncludeMetadataInDatabase has been removed and being replaced with a
pluggable convention that does the same thing for you:
modelBuilder.Conventions
.Remove<System.Data.Entity.Database.IncludeMetadataConvention>();
The equivalent in CTP5 to switch off initializer logic: In your Application_Start in Global.asax, enter the following:
System.Data.Entity.Database.DbDatabase.SetInitializer<MyDBContext>(null);
In EF 4.1
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
}
Have been looking for this all over, and I had to find the answer right after posting my question, DUH. Right from the ADO.NET team blog:
In CTP5 we have removed the need to
perform additional configuration when
mapping to an existing database. If
Code First detects that it is pointing
to an existing database schema that it
did not create then it will ‘trust
you’ and attempt to use code first
with the schema. The easiest way to
point Code First to an existing
database is to add a App/Web.config
connection string with the same name
as your derived DbContext (...)