EF Initializer with multiple contexts for one database - c#

I have an existing application with a SQL database that has been coded using a database first model (I create an EDMX file every time I have schema changes).
Some additional development (windows services which support the original application) has been done which uses EF POCO/DbContext as the data layer instead of an EF EDMX file. No initializer settings were ever configured in the DbContexts, but they never modified the database as the DbSet objects always matched the tables.
Now, I've written a seperate application that uses the existing database but only its own, new tables, which it creates itself using EFs initializer. I had thought this would be a great time to use EF Code First to handle managing these new tables. Everything worked fine the first time I ran the application, but now I am getting this error from some of my original EF POCO DbContexts (which never used an initializer).
The model backing the 'ServerContext' context has changed since the
database was created. Consider using Code First Migrations to update
the database
After some investigation, I've discovered that EF compares a hash of its schema with some stored hash in the sql server somewhere. This value doesn't exist until a context has actually used an initializer on the database (in my case, not until the most recent application added its tables).
Now, my other DbContexts throw an error as they read the now existing hash value and it doesn't match its own. The EF connection using the EDMX doesn't have any errors.
It seems that the solution would be to put this line in protected override void OnModelCreating(DbModelBuilder modelBuilder) in all the DbContexts experiencing the issue
Database.SetInitializer<NameOfThisContext>(null);
But what if later on I wanted to write another application and have it create its own tables again using EF Code first, now I will never be able to reconcile the hash between this theoretical even newer context and the one that is causing the issue right now.
Is there a way to clear the hash that EF stores in the database? Is EF smart enough to only alter tables that exist as a DbSet in the current context? Any insights appreciated.

Yes, Bounded DB contexts is actually good practice.
eg a base context class, to use common connection to DB, each sub class, uses the
Database.SetInitializer(null); as you suggest.
Then go ahead and have 1 large context that has the "view of the DB" and this context is responsible for all migrations and ONLY that context shoudl do that. A single source of truth.
Having multiple contexts responsible for the DB migration is a nightmare I dont think you will solve.
Messing with the system entries created by code first migrations can only end in tears.
Exactly the topic you describe I saw in A julie Lerman video.
Her suggested solution was a single "Migration" context and then use many Bounded DB contexts.
In case you have a pluralsight account:
http://pluralsight.com/training/players/PsodPlayer?author=julie-lerman&name=efarchitecture-m2-boundedcontext&mode=live&clip=11&course=efarchitecture

What EF version are you using? EF Code First used to store hash of the SSDL in the EdmMetadata table. Then in .NET Framework 4.3 thingh changed a little bit and the EdmMetadata table was replaced by __MigrationsHistory table (see this blog post for more details). But it appears to me that what you are really looking after is multi-tenant migrations where you can have multiple context using the same database. This feature has been introduced in EF6 - (currently Aplpha2 version is publicly available) Also, note that EdmMetadata/__MigrationHistory tables are specific to CodeFirst. If you are using the designer (Model First/Database First) no additional information is stored in the database and the EF model is not checked whether it matches the database. This can lead to hard to debug bugs and/or data corruption.

Related

Problems with updating Views in Entity Framework

For some reasons we need to update Views inside the Entity Framework.
So we followed this solution on another question and it worked like a charm!
BUT here is the problem:
if we update our model (for some new fields or tables/views) the complete Mappings are destroyed and after updating we get the Warning
Error 11007: Entity type 'UpdateView1' is not mapped.
After this it's not even possible to load the entities because all Mappings are lost.
So how to design the views to be able to post updates using the Views AND to be able to update the edmx file?
MS is dropping support for EDMX files going forward in Entity Framework - in part due to the difficulty of keeping the database, EDMX, and POCOs all sync'd, as you are experiencing. (Anyone can edit any of the 3, then changes are lost when a sync is done).
So they recommend using the Code First approach. Code First is a bit of a misnomer and causes some confusion.
Code First doesn't mean you have to start with code.
You can start with the database and then write your POCOs to match it (as in your case). Doing so allows you to preserve all your mappings and such because you just adjust your code to match the structure already present in your database.
Another misconception is that you have to use migrations. You do not. You are welcome to not enable migrations and manually edit both the database schema and POCOs as long as you ensure they remain in sync.

entity framework with existing, non related database

I have an odd situation. I am working on a project with a very large existing database that is completely unrelated, but does contain corresponding table id's. It's as if someone copied the database but never related the tables.
In Entity Framework, is there a way to go EF code first and create the relationships in code, but Not apply those relationships in the database? I would like to go through and relate the database but the client doesn't want to pay to fix it.
Thanks!
In this instance, it seems you would be best to add relationships directly to your database (or to a duplicated database for testing/staging) and then just update your entities using your test connection and regression test your app.

EntityFramework 6 Migrations for both existing and new databases?

In our software, we have a customer base with existing databases. The databases are currently accessed via EntitySpaces, but we'd like to switch to EntityFramework (v6), as EntitySpaces is no longer supported. We'd also like to make use of the migrations feature. Automatic migrations are disabled, since we only want to allow database migration to an admin user.
We generated the EF model from an existing database. It all works pretty well, but the real problem we have, is, programmatically distinguishing between existing databases that match the model but have not yet been converted to EF (missing MigrationsHistory table), and empty/new databases. Converting existing databases works well with an empty migration, but for new databases we also need a migration containing the full model. Having an initial migration in the migration chain always clashes with existing databases. Of course we could create a workaround with external SQL scripts or ADO commands, creating and populating the MigrationsHistory table. But that is something we'd like to avoid, because some of our clients use MsSql databases, some use Oracle. So we'd really like to keep the abstraction layer provided by EF.
Is there a way to get EF to handle both existing, and new databases through code-based migrations, without falling back to non-EF workarounds?
My original suggestion was to trap the exception raised by CreateTable, but it turns out this is executed in a different place so this cannot be trapped within the exception.
The simplest method of proceeding will be to use the Seed method to create your initial database if it is not present. To do this...
Starting from a blank database, add an Initial Create migration and grab the generated SQL
Add-Migration InitialCreate
Update-Database -Script
Save this script. You could add it to a resource, static file or even leave it inline in your code if you really want, it's up to you.
Delete all of the code from the InitialCreate migration (leaving it with a blank Up() and Down() function). This will allow your empty migration to be run, causing the MigrationHistory table to be generated.
In your Migration configuration class, you can query and execute SQL dynamically using context.Database.SqlQuery and context.Database.ExecuteSqlCommand. Test for the existence of your main tables, and if it's not present, execute the script generated above.
This isn't very neat, but it's simple to implement. Test it well, as the Seed method runs after EVERY migration runs, not just the initial one. This is why you need to test for the existence of a main table before you do anything.
The more complicated approach would be to write a "CreateTableIfNotExists" method for migrations, but this will involve use of Reflection to call internal methods in the DbMigration class.

How to get entity framework to realize the model and the DB are in sync

I am using Entity Framework code first for the first time in a production environment. Everything went fine until we got the DB up and had put some of the data in it and then to get some of the data we were importing from another location we had to change field lengths. So we made some of the fields nvarchar(99) instead of nvarchar(50).
That went fine and the application still worked but I knew I needed to change the data annotation or it would blow up later when it loaded and tried to save a too long field. When I did that the app blew up even though the model and the db are now matching. So I thought that it was the hash in the metadata table so I thought I'd be clever and make a new DB and take the hash from there and copy it. That did not work and in fact now I cannot get my app to connect to the test db that we have data loaded in at all.
I do not want to drop and recreate this database. I want entity framework to realize that the model and the schema do in fact match. Is there any way for me to do this? Also why did copying the metadata from a DB that entity framework created with this model not work?
Entity Framework Code First creates a EdmMetadata table and saves a hash of your Model classes in it. When you change something in the Model, the hash of the new Model classes doesn't match what's in the EdmMetadata table anymore, and the app should "blow up" at runtime. What you need to do to keep using the same database without dropping it, is to delete the EdmMetadata table. This way EF will not do that check and will try to proceed with the access to the DB.
Check this video tutorial (skip to 8:10 of the "When Classes Change" section).
Sorry I fixed this. Removing the metadata worked. But turns out I had updated to a more recent version of EntityFramework accidentally while trying to fix my problem and this more recent version expected different naming conventions for the Database. In any case recreating the many-to-many group person table with a script from a DB created by Entity Framework and deleting the metadata fixed the problem.

Keep Database Content On Model Change

Using the code-first approach available in the new 4.1 RC.
Is there any way to persist the current data stored in a database when the mode changes? The database is created by the entity framework, and usually the database is dropped and recreated on model changes.
Obviously as soon as the model is changed it will not be possible to use the context object to connect to the database to retrieve the data, so what are the options?
Code first doesn't support database migration / evolution yet. If you want to do incremental DB development use model first (EDMX) with DbContext Generator T4 template and Entity designer database generation pack which is able to create diff. scripts from the model.
From Scott Gu:
Importantly, though, the auto-create
database option is just an option – it
is definitely not required. If you
point your connection-string at an
existing database then EF “code first”
will not try and create one
automatically. The auto-recreate
option also won’t be enabled unless
you explicitly want EF to do this – so
you don’t need to worry about it
dropping and recreating your database
unless you’ve explicitly indicated you
want it to do so.

Categories