I have started introducing code first migrations in the project, however I have stumbled upon several issues I am not able to resolve.
The setup is, that the project has two targets: an online client, which connects to a WCF service and uses a regular SQL Server database. Also included is an offline client, which holds all data locally and uses a SQL Server CE database.
This already works. Now I need to introduce a way to migrate both database versions. Of course I would prefer using the same migrations code. What I have done so far, is:
enable-migrations (using a localhost SQL Server db, where I create the migrations against)
add-migration (for the initial migration)
One problem is that when I create my SQL Server CE database using CreateIfNotExists initializer, the db will be created with all string properties mapped to nvarchar columns.
However, when I start using migrations, and create my db with a MigrateToLatestVersion initializer, the db will created, but the string properties are now mapped to NTEXT columns.
A subsequent seed fails, because I get the following exception:
The ntext and image data types cannot be used in WHERE, HAVING, GROUP BY, ON, or IN clauses, except when these data types are used with the LIKE or IS NULL predicates.
I have tried to force the model builder to use nvarchar for strings, but to no avail. It is completely ignored.
modelBuilder.Properties<string>().Configure(config => config.HasColumnType("nvarchar"));
I am kind of lost here really.
I have found the solution and it is rather embarrasing, really.
I forgot to recreate my initial migration, after i added my modelbuilder code for the string properties.
I just recreated it now and it works.
Related
I have inherited an entity framework application that i have been tasked to create within a separate environment with a completely separated database as well on a new db server. Seems easy enough. I backup the database from the original and restore it on the new database server. the data is the exact same at this point.
For testing purposes i change the local connection string to the new database server and run my web app locally. I get an error in the browser that is "MySql.Data.MySqlClient.MySqlException: Can't write; duplicate key in table '#sql-3b87_2d5f91'" i dont even have a table with that name and have no idea where it comes from. entity framework also creates duplicate tables for all of my tables except for migrations table.
I have tried other things as well, after restoring the db in the new db server to the original again, i have tried running 'update-database' and the same issues happen.
Now if i disregard restoring the new database with the backup from the original and run "update-database" on the new database server. it creates the schema correctly, but it lacks the data i need for testing.
Any ideas why this may be happening? i would like to avoid writing a sql script to transfer data.
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.
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.
I am working on a project which uses Entity Framework 4.1 for persisting our various objects to the database (code first).
I am testing in Visual Studio with a local SQL Express DB, and our Jenkins server deploys committed code to a testing server. When this happens I temporarily change my local connection string to point to the testing DB server and run a unit test to re-create the test database so that it matches our latest entities, etc.
I've recently noticed our testing server is giving this error:
The model backing the 'EntityFrameworkUnitOfWork' 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.
This is usually an indication that our code has changed and I need to run the unit test to re-create the database. Except I just did that! I don't believe there is anything wrong with our deployment process - the DLLs on the test server seem to be the same versions as in my local environment. Are there any other settings or environment factors that can cause this error about the model having changed since the database was created?
I'm new here - thanks for any help!
The error you see means that the model hash stored in EdmMetadata table is different from the model hash computed from the model in the application. Because you are running database creation from a different application (your dev. application) it is possible that those two differ. Simple advice here is: don't use different applications for database creation and instead let your main application create the database (either automatically or for example with some admin interface).
As another option you should be able to turn off this check completely by removing the convention responsible for these checks:
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
Model hash computation is dependent on current entities in your application (any simple change result in different model hash) and on database server versions / manifest. For example a model deployed on SQL server 2005 and 2008 will have different model hash (Express vs. Full or 2008 vs. 2008 R2 should not result in different model hash).
This can happen due to reflection ordering differences across different platforms. To verify, you can use the EdmxWriter API to compare the EDMX from both environments. If any of the tables have different column ordering, then this is the issue.
To workaround, you can change the way your test database gets updated such that it is updated from your test server rather than your local box.
We are going to fix this issue in the next release.
In the code-first approach, the SSDL is generated during the execution of the code. One of the informations included in the generated SSDL is the name of the provider used in the DbConnection. As you said, you're connecting to different databases engines, so you must use two different providers. This completly changes the output of the hashing function.
The below code was extracted from the EntityFramework assembly:
using (XmlWriter writer = XmlWriter.Create(output, settings))
{
new SsdlSerializer().Serialize(database, providerInfo.ProviderInvariantName, providerInfo.ProviderManifestToken, writer);
}
This might help and the link to Scott G blog will sure be a solution to your problem check this question link
Edit 1: this is the link to Scott G blog
Edit 2: You may also check this if you use a database first on integration server
Edit 3: This is a more detailed answer like the one from Scott G
Are the two servers running your application running different operating systems (or service packs?) It appears the SHA256CryptoService used can throw a PlatformNotSupportedException which causes it to fallback to another method.
http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha256cryptoserviceprovider.sha256cryptoserviceprovider.aspx
// System.Data.Entity.Internal.CodeFirstCachedMetadataWorkspace
private static SHA256 GetSha256HashAlgorithm()
{
SHA256 result;
try
{
result = new SHA256CryptoServiceProvider();
}
catch (PlatformNotSupportedException)
{
result = new SHA256Managed();
}
return result;
}
You may be able to test this by using reflection to invoke the following 2 (internal/private) methods on each server.
MetaDataWorkspace.ToMetadataWorkspace(DbDatabaseMapping, Action<string>)
CodeFirstCachedMetadataWorkspace.ComputeSha256Hash(string xml);
Entity Framework code first creates a table called EdmMetadata. It keeps a hash of your current model. Once you run the application EF checks if the model being used is the same as the model that the db 'knows about'.
If you want to perform database migration, I suggest you use EF Code first migrations though it's still an alpha.
If you don't want to use migrations you can either:
handle the schema change manually - that means moving the content of the EdmMetadata table to the test server along with all the changes
or
set the db initializer to DropCreateDatabaseIfModelChanges (or better something derived from it and use the Seed() method to write the initial data). To set the initialzer either call Database.SetInitializer() on application start or use the appSettings
<add key="DatabaseInitializerForType Fully.Qualified.Name.Of.Your.DbContext," value="Fully.Qualified.Name.Of.The.Initializer" />
I only accidentally renamed my .mdf file and got this error. So look also for this.
In most asp.net applications you can change the database store by modifing the connectionstring at runtime. i.e I can change from using a test database to a production database by simply changing the value of the "database" field in the connectionstring
I'm trying to change the schema (but not necessarily the database itself) with entity framework but no luck.
The problem I'm seeing is the that the SSDL content in the edmx xml file is storing the schema for each entityset.
see below
<EntitySet
Name="task"
EntityType="hardModel.Store.task"
store:Type="Tables"
Schema="test" />
Now I have changed the schema attribute value to "prod" from test and it works..
But this does not seem to be a good solution.
I need to update evert entity set as well as stored procedures ( I have +50 tables )
I can only do this an compile time?
If I then try to later update the Entity model-entityies that already exist are being read due to EF not recognizing that the table already exists in the edm.
Any thoughts?
I have this same issue and it's really rather annoying, because it's one of those cases where Microsoft really missed the boat. Half the reason to use EF is support for additional databases, but unless you go code first which doesn't really address the problem.
In MS SQL changing the schema makes very little sense, because the schema is part of the identity of the tables. For other types of databases, the schema is very much not part of the identity of the database and only determines the location of the database. Connect to Oracle and changing the database and changing the schema are essentially synonymous.
Update Upon reading your comments it's clear that you're wanting to change the referenced schema for each DB, not the database. I've edited the question to clarify this and to restore the sample EDMX you provided which was hidden in the original formatting.
I'll repeat my comment below here:
If the schemata are in the same DB, you can't switch these at runtime (except with EF 4 code-only). This is because two identically-named and structured tables in two different schemata are considered entirely different tables.
I also agree with JMarsch above: I'd reconsider the design of putting test and production data (or, actually, 'anything and production data') in the same DB. Seems like an invitation to disaster.
Old answer below.
Are you sure you're changing the correct connection string? The connection string used by the EF is embedded inside the connection string which specifies the location of CSDL/SSDL/etc. It's common to have a "normal" connection string for use by some other part of your app (e.g., ASP.NET membership). In this case, when changing DBs you must update both of your connection strings.
Similarly, if you update the connection string at runtime then you must use specific tools for this, which understand the EF connection string format and are separate from the usual connection string builder. See the example in the link. See also this help on assigning EF connection strings.
The easiest way to solve the problem is to manualy remove all entries like 'Schema="SchemaName"' from the SSDL part of the model.
Everything works propely in this case.
Sorry its not a robust answer but I found this project on codeplex ( as well as this question ) while googling around for a similar problem:
http://efmodeladapter.codeplex.com/
The features include:
Run-time adjustment of model schema,
including:
Adjusting data-level table
prefixes or suffixes
Adjusting the
owner of database objects
Some code from the docs:
public partial class MyObjectContext : BrandonHaynes.ModelAdapter.EntityFramework.AdaptingObjectContext
{
public MyObjectContext()
: base(myConnectionString,
new ConnectionAdapter(
new TablePrefixModelAdapter("Prefix",
new TableSuffixModelAdapter("Suffix")),
System.Reflection.Assembly.GetCallingAssembly()))
{
...
}
}
Looks like its exactly what your looking for.
The connection string for EF is in the config file. There is no need to change the SSDL file.
EDIT
Do you have the prod and test schema in the same database?
If Yes you can fix it by using a seperate database for prod and test. Using the same schema name in both databases.
If No you can fix it by Using the same schema name in both databases.
If you will absolutly have different schema names, create two EF models, one for test and one for prod, then select which on to use in code based on a value in your config file.
When I create a new "ADO.NET Entity Data Model", there are two properties "Entity Container Name" and "Namespace" available for editing in design view.. Using the namespace.EntityContainerName, you can create a new instance specifying a connection string.
MyEntities e = new MyEntities("connstr");
e.MyTable.Count();
I'm not sure if this helps you or not, good luck!
Also, this is a good case for multiple layers (doesn't have to be projects, but could be).
Solution
* DataAccess - Entities here
* Service - Wraps access to DataAccess
* Consumer - Calls Service
In this scenario, the consumer calls service, passing in whatever factor determines which connection string is used. The service then instantiates an instance of data access passing in the appropriate connection string and executes the consumer's query.
Here is a similar question with a better answer:
Changing schema name on runtime - Entity Framework
The solution that worked for me was the one written by Jan Matousek.
Solved my problem by moving to sql server and away from mysql.
Mysql and Mssql interpret "schemas" differently. Schemas in mysql are the same/synonyms to databases. When I created the model the schema name..which is the same as the database name is hard coded in the generated model xml. In Mssql the schema is by default "dbo" which gets hard coded but this isnt an issue since in mssql schemas and databases are different.