EF code first migration error "Object has been disconnected or does not exist at the server" - entity-framework

I am using Entity Framework 6.1.1 on SQL Server 2008 and I have a long running code first migration (about 20 minutes). It gets to the end and then gives the following error.
System.Runtime.Remoting.RemotingException: Object '/f10901d8_94fe_4db4_bb9d_51cd19292b01/bq6vk4vkuz5tkri2x8nwhsln_106.rem' has been disconnected or does not exist at the server.
at System.Data.Entity.Migrations.Design.ToolingFacade.ToolLogger.Verbose(String sql)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement, DbInterceptionContext interceptionContext)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsInternal(IEnumerable`1 migrationStatements, DbTransaction transaction, DbInterceptionContext interceptionContext)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsInternal(IEnumerable`1 migrationStatements, DbConnection connection)
at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClass30.<ExecuteStatements>b__2e()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.<Execute>b__0()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action operation)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements, DbTransaction existingTransaction)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.DbMigrator.ExecuteOperations(String migrationId, XDocument targetModel, IEnumerable`1 operations, IEnumerable`1 systemOperations, Boolean downgrading, Boolean auto)
at System.Data.Entity.Migrations.DbMigrator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.DbMigrator.UpdateInternal(String targetMigration)
at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClassc.<Update>b__b()
at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force)
at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()
at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
The point of the migration is to update a field in the database that stores the MIME type of some binary data. It loops through every row, reads the binary data, attempts to determine what kind of content it is, then writes the appropriate MIME type value into the that row.
The script below uses ADO.NET to generate a list of update statements to run. I use ADO.NET because I must use .NET's imaging libraries (System.Drawing.Imaging.ImageFormat) to determine the type of binary content in each row (it'll be a jpeg, png, or pdf).
public override void Up()
{
List<string> updateStatements = new List<string>();
using(SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings["ConnectionString"]))
{
SqlCommand cmd = new SqlCommand("SELECT Table1ID, Image FROM Table1"), conn);
conn.Open();
//read each record and update the content type value based on the type of data stored
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
long idValue = Convert.ToInt64(reader["Table1ID"]);
byte[] data = (byte[])reader["Image"];
string contentType = GetMimeType(data);
updateStatements.Add(string.Format("UPDATE Table1 SET Content_Type = {0} WHERE Table1ID = {1}", contentType, idValue));
}
}
}
foreach (string updateStatement in updateStatements)
Sql(updateStatement);
}
public string GetMimeType(byte[] document)
{
if (document != null && document.Length > 0)
{
ImageFormat format = null;
try
{
MemoryStream ms = new MemoryStream(document);
Image img = Image.FromStream(ms);
format = img.RawFormat;
}
catch (Exception)
{
/* PDF documents will throw exceptions since they aren't images but you can check if it's really a PDF
* by inspecting the first four bytes with will be 0x25 0x50 0x44 0x46 ("%PDF"). */
if (document[0] == 0x25 && document[1] == 0x50 && document[2] == 0x44 && document[3] == 0x46)
return PDF;
else
return NULL;
}
if (format.Equals(ImageFormat.Jpeg))
{
return JPG;
}
else if (format.Equals(System.Drawing.Imaging.ImageFormat.Png))
{
return PNG;
}
}
return NULL;
}
I've seen this five year old post and the articles that it links to do not seem to exist anymore. At least I can't find them.
Does anyone know what's going on here?
-- UPDATE --
This appears to have something to do with how long the migration takes to run. I created a migration that does absolutely nothing other than sleep for 22 minutes
public override void Up()
{
System.Threading.Thread.Sleep(1320000);
}
and I got the same error. So it appears to be a timeout thing. I'm not 100% what object on the server they are referring to and I can't find much on this issue as it relates to code first migrations.
I tried setting the CommandTimeout property in the migrations Configuration.cs file to 5000 but it didn't help. I also attempted to set the SQL Server's Remove query timeout setting to 0 to prevent any timeouts but it didn't help either.

Poached from [GitHub EntityFramework 6 Issue #96][https://github.com/aspnet/EntityFramework6/issues/96#issuecomment-289782427]
The issue is that the ToolLogger lease lifetime (base class
MigrationsLogger is a MarshalByRefObject) is at the default (5
minutes). The ToolingFacade creates the logger, which lives in the
main program's app domain. The migrations run in a different app
domain. If a migration takes longer than 5 minutes, the attempt to log
any further information results in this error. A solution would be to
increase the lease lifetime in the main program. So... in the main
program, prior to creating the ToolingFacade, set the lease lifetime
to a longer time period:
using System.Runtime.Remoting.Lifetime;
...
LifetimeServices.LeaseTime = TimeSpan.FromHours(1);

It's a known issue in Entity Framework 6 for scripts that take a long time to complete.
A workaround is to generate only SQL script via the Update-Database command and execute the generated SQL directly on the SQL Server. In order to generate only the SQL you have to use the -Script flag:
Update-Database -Script

This has been causing us headaches. The problem appears to be due to the design of the EF migration utility. The program creates a new AppDomain in which to run migrations. The logging for the new AppDomain is handled in the original AppDomain (which is why remoting gets involved). Apparently the logger gets GC'ed if an individual migration takes too much time. I've verified this by replacing all the logger calls with Console.WriteLine - which makes the problem go away. There may be a fix by altering the migrate.exe tool (but may possibly require altering EntityFramework assembly itself).

I had this problem because the connection string in my web.config was pointing to the wrong server name.
Actually, I had to change my c:\windows\system32\drivers\etc\host file to specify correct IP address for this DB host name.
Just make sure your DB server is accessible.

Related

CodeFluent persistence race condition

As soon as the database becomes slow for some reason ( long running query, backup, performance analyzer)
My Web Application start getting, eventually the following errors:
System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
at System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)
at System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at CodeFluent.Runtime.CodeFluentPersistence.InternalExecuteNonQuery(Boolean firstTry)
at CodeFluent.Runtime.CodeFluentPersistence.InternalExecuteNonQuery(Boolean firstTry)
.... _> stack trace continues to my code
CodeFluent.Runtime.CodeFluentRuntimeException: CF1044: Nested persistence command is not supported. Current command: '[Contract_Search]', nested command: '[zref_template_document_LoadBlobFile]'.
at CodeFluent.Runtime.CodeFluentPersistence.CreateStoredProcedureCommand(String schema, String package, String intraPackageName, String name)
at CodeFluent.Runtime.BinaryServices.BinaryLargeObject.GetInputStream(CodeFluentContext context, Int64 rangeStart, Int64 rangeEnd)
.... _> stack trace continues to my code
The second error CF1044 happens when I open two browser windows and doing different actions. Search in one, generate a document in another.
It's difficult to reproduce. It never happens the same way.
There is a race condition somewhere I can't figure out.
Here is what actually worked for me:
public byte[] GetRtfDocumentStreamBuffer(TemplateDocumentType templateType, int culture)
{
var template = TemplateDocument.LoadActiveByDocumentTypeAndLcid(DateTime.Today, templateType.Id, culture);
var resultStream = new MemoryStream();
using (var cf = CodeFluentContext.GetNew(Constants.MyApplicationStoreName))
using (var templateStream = template.File.GetInputStream(cf, 0, 0))
using (var resultWriter = new StreamWriter(resultStream, Encoding.GetEncoding("windows-1252")))
{
GenerateRtfDocument(....);
resultWriter.Flush();
}
return resultStream.GetBuffer();
}
what I saw in decompiled cf runtime that is CodeFluentContext.Dispose() call CodeFluentPersistence.Dispose() which close reader and dispose connection.

How to create a LocalDB instance for NEventStore

I'm trying to use LocalDb with NEventStore but, even though I think I have set-up the database correctly, I keep getting the following exception:
NEventStore.Persistence.StorageUnavailableException: Invalid object name 'Snapshots'.
In code I configure NEventStore to use the database like this:
this.EventStore = Wireup.Init()
.LogToOutputWindow()
.UsingInMemoryPersistence()
.UsingSqlPersistence("DefaultConnection")
.WithDialect(new MsSqlDialect())
.UsingJsonSerialization()
.LogToOutputWindow()
.Build();
I have the following database connection in my web.config file:
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\MyDatabase.mdf;Initial Catalog=MyDatabase;Integrated Security=True" providerName="System.Data.SqlClient" />
And using Visual Studio I've added an SqlServerDatabase (MyDatabase.mdf) to the App_Data folder of my Asp.net MVC 5 project. NEventStore seems to be able to open the database (if I remove MyDatabase.mdf from my project I get a different exception). But it seems its unable to initialize the database correctly. When I browse the database, after running into the error message, I see that no tables have been created.
What makes this extra strange is that, if this document is correct, Snapshots should be the second table made. So it seems it has no problem creating the first one.
The complete stack trace for the StorageUnavailableException
at NEventStore.Persistence.Sql.SqlDialects.PagedEnumerationCollection.OpenNextPage() in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\Persistence\Sql\SqlDialects\PagedEnumerationCollection.cs:line 200
at NEventStore.Persistence.Sql.SqlDialects.PagedEnumerationCollection.MoveToNextRecord() in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\Persistence\Sql\SqlDialects\PagedEnumerationCollection.cs:line 146
at NEventStore.Persistence.Sql.SqlDialects.PagedEnumerationCollection.System.Collections.IEnumerator.MoveNext() in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\Persistence\Sql\SqlDialects\PagedEnumerationCollection.cs:line 70
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
at NEventStore.Persistence.Sql.SqlPersistenceEngine.GetSnapshot(String bucketId, String streamId, Int32 maxRevision) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\Persistence\Sql\SqlPersistenceEngine.cs:line 225
at NEventStore.Persistence.PipelineHooksAwarePersistanceDecorator.GetSnapshot(String bucketId, String streamId, Int32 maxRevision) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\Persistence\PipelineHooksAwarePersistanceDecorator.cs:line 45
at NEventStore.AccessSnapshotsExtensions.GetSnapshot(IAccessSnapshots accessSnapshots, String bucketId, Guid streamId, Int32 maxRevision) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\AccessSnapshotsExtensions.cs:line 49
at CommonDomain.Persistence.EventStore.EventStoreRepository.GetSnapshot(String bucketId, Guid id, Int32 version) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\CommonDomain\Persistence\EventStore\EventStoreRepository.cs:line 147
at CommonDomain.Persistence.EventStore.EventStoreRepository.GetById[TAggregate](String bucketId, Guid id, Int32 versionToLoad) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\CommonDomain\Persistence\EventStore\EventStoreRepository.cs:line 54
at CommonDomain.Persistence.EventStore.EventStoreRepository.GetById[TAggregate](Guid id, Int32 versionToLoad) in c:\TeamCity\buildAgent\work\38b1777f2112a252\src\NEventStore\CommonDomain\Persistence\EventStore\EventStoreRepository.cs:line 44
at CapraLibraShop.DataModel.Repositories.UserAggregateRepository.UserWithEmailExists(EmailAddress emailAddress) in D:\Projects\C#\CapraLibraShop\CapraLibraShop.DataModel\Repositories\UserAggregateRepository.cs:line 22
at CapraLibraShop.Controllers.AccountController.Register() in D:\Projects\C#\CapraLibraShop\CapraLibraShop\Controllers\AccountController.cs:line 55
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()
I literally found the answer two minutes after looking. But since I had a hard time Googling this answer I think it would be nice to place the answer here, instead of deleting the question.
I forgot to initialize the storage engine. I overlooked it because of the fluid syntax. The correct way to let NEventStore initialize the database is by including the InitializeStorageEngine method after you have selected the database type:
this.EventStore = Wireup.Init()
.LogToOutputWindow()
.UsingInMemoryPersistence()
.UsingSqlPersistence("DefaultConnection")
.WithDialect(new MsSqlDialect())
.InitializeStorageEngine() // The oh so important line!
.UsingJsonSerialization()
.LogToOutputWindow()
.Build();

Data Entities Add Range quit working

Like the title suggests I have a small program that has been running in production for the last 3 months. Last week it started to error out on an AddRange line with this error message:
"Message=Keyword not supported: 'file'."
And nothing in the inner exception. Here is the offending function where I can no longer get to the SaveChanges() line.
private static void SaveToDB(List<MarketNew> inMarketNews)
{
proxy.MarketNews.AddRange(inMarketNews);
proxy.SaveChanges();
}
cheers
bob
edit-
If I try to manually add them one at a time I still receive the following exception.
System.ArgumentException was caught
HResult=-2147024809
Message=Keyword not supported: 'file'.
Source=System.Data
StackTrace:
at System.Data.Common.DbConnectionOptions.ParseInternal(Hashtable parsetable, String connectionString, Boolean buildChain, Hashtable synonyms, Boolean firstKey)
at System.Data.Common.DbConnectionOptions..ctor(String connectionString, Hashtable synonyms, Boolean useOdbcRules)
at System.Data.SqlClient.SqlConnectionString..ctor(String connectionString)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnectionOptions(String connectionString, DbConnectionOptions previous)
at System.Data.ProviderBase.DbConnectionFactory.GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, DbConnectionOptions& userConnectionOptions)
at System.Data.SqlClient.SqlConnection.ConnectionString_Set(DbConnectionPoolKey key)
at System.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.<SetConnectionString>b__18(DbConnection t, DbConnectionPropertyInterceptionContext`1 c)
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext](TTarget target, Action`2 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.SetConnectionString(DbConnection connection, DbConnectionPropertyInterceptionContext`1 interceptionContext)
at System.Data.Entity.Infrastructure.SqlConnectionFactory.CreateConnection(String nameOrConnectionString)
at System.Data.Entity.Internal.LazyInternalConnection.Initialize()
at System.Data.Entity.Internal.LazyInternalConnection.get_ProviderName()
at System.Data.Entity.Internal.LazyInternalContext.get_ProviderName()
at System.Data.Entity.Internal.DefaultModelCacheKeyFactory.Create(DbContext context)
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.Initialize()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
at System.Data.Entity.Internal.Linq.InternalSet`1.AddRange(IEnumerable entities)
at System.Data.Entity.DbSet`1.AddRange(IEnumerable`1 entities)
at GetMarketNews.Program.SaveToDB(List`1 inMarketNews) in e:\Tableau\Custom Utilities\MarketNews\GetMarketNews\GetMarketNews\Program.cs:line 195
InnerException:
The exception indicates that there is a problem with your connection string. While the program itself may not have been changed in months, can you confirm that the config file (or however you set your connection string) has not been changed?
If you still can't find it from this, I would suggest you check out the value of the connection string at runtime (e.g. put a breakpoint on the AddRange line, and look at proxy.Database.ConnectionString). I suspect you'll find the "file" keyword in the connection string.

EF5 Code First Migrations: "Column names in each table must be unique" error after using RenameColumn

We're using Entity Framework 5.0 Code First and Automatic Migrations.
I had a class like so:
public class TraversalZones
{
public int Low { get; set; }
public int High { get; set; }
}​
Then we realized these properties weren't really the right names, so we changed them:
public class TraversalZones
{
public int Left { get; set; }
public int Top { get; set; }
}​
The rename refactored properly throughout the project, but I know Automatic Migrations aren't smart enough to pick up these explicit renames in the IDE, so I first checked to verify the only pending migration was this column rename:
update-database -f -script
Sure enough it just showed the SQL dropping Low and High and adding Left and Top. I then added a manual migration:
add-migration RenameColumns_TraversalZones_LowHigh_LeftTop
And fixed up the generated code to simply:
public override void Up()
{
RenameColumn("TraversalZones", "Low", "Left");
RenameColumn("TraversalZones", "High", "Top");
}
public override void Down()
{
RenameColumn("TraversalZones", "Left", "Low");
RenameColumn("TraversalZones", "Top", "High");
}
​
I then updated the db:
update-database -verbose
And got 2 column renames, just like I was expecting.
Several migrations later I backed up Production and Restored it to a local DB to test the code on this DB. This DB had the TraversalZones table already created in it, with the old column names (Low and High) I of course began by updating it:
update-database -f -verbose
And the rename commands appeared in the output - all appeared well:
EXECUTE sp_rename #objname = N'TraversalZones.Low', #newname = N'Left', #objtype = N'COLUMN'
EXECUTE sp_rename #objname = N'TraversalZones.High', #newname = N'Top', #objtype = N'COLUMN'
[Inserting migration history record]
I then ran my code, and it errored out telling me the database had changed since last run, and that I should run update-database... .
So I ran it again:
update-database -f -verbose
And am now stuck on this error:
No pending code-based migrations. Applying automatic migration:
201212191601545_AutomaticMigration.
ALTER TABLE [dbo].[TraversalZones] ADD [Left] [int] NOT NULL DEFAULT 0
System.Data.SqlClient.SqlException (0x80131904): Column names in each table must be unique. Column name 'Left' in table 'dbo.TraversalZones' is specified more than once.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Entity.Migrations.DbMigrator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.DbMigrator.ExecuteOperations(String migrationId, XDocument targetModel, IEnumerable`1 operations, Boolean downgrading, Boolean auto)
at System.Data.Entity.Migrations.DbMigrator.AutoMigrate(String migrationId, XDocument sourceModel, XDocument targetModel, Boolean downgrading)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.AutoMigrate(String migrationId, XDocument sourceModel, XDocument targetModel, Boolean downgrading)
at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.RunCore()
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
ClientConnectionId:c40408ee-def3-4553-a9fb-195366a05fff
Column names in each table must be unique. Column name 'Left' in table 'dbo.TraversalZones' is specified more than once.​
So, clearly Migrations is confused as to whether the column "Left" still needs to make it into this table; I would assume RenameColumn would leave things in the proper state, but it appears it has not.
When I dump what it's attempting to do to a update-database -f -script, I get it trying to do exactly what it would have done if the manual migration were not there:
ALTER TABLE [dbo].[TraversalZones] ADD [Left] [int] NOT NULL DEFAULT 0
ALTER TABLE [dbo].[TraversalZones] ADD [Top] [int] NOT NULL DEFAULT 0
DECLARE #var0 nvarchar(128)
SELECT #var0 = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'dbo.TraversalZones')
AND col_name(parent_object_id, parent_column_id) = 'Low';
IF #var0 IS NOT NULL
EXECUTE('ALTER TABLE [dbo].[TraversalZones] DROP CONSTRAINT ' + #var0)
ALTER TABLE [dbo].[TraversalZones] DROP COLUMN [Low]
DECLARE #var1 nvarchar(128)
SELECT #var1 = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'dbo.TraversalZones')
AND col_name(parent_object_id, parent_column_id) = 'High';
IF #var1 IS NOT NULL
EXECUTE('ALTER TABLE [dbo].[TraversalZones] DROP CONSTRAINT ' + #var1)
ALTER TABLE [dbo].[TraversalZones] DROP COLUMN [High]
INSERT INTO [__MigrationHistory] ([MigrationId], [Model], [ProductVersion]) VALUES ('201212191639471_AutomaticMigration', 0x1F8B08000...000, '5.0.0.net40')
This appears to be a bug in Migrations.
The workaround, obviously, is this:
update-database -f -script
Which you can see the results of in my question. Then I tossed everything from the script but the last line, and ran that against the DB to let Migrations know: We already renamed that column, cut it out.
I can now proceed with this copy of the database, but I'm concerned every migration against copies of Production (until Production itself has been migrated) will keep having this issue. How can I resolve this properly without this workaround?
Update
This was in fact an issue in every other instance including Production. The dirty solution was to generate a SQL script (update-database -f -script), after committing the generated version and the fixed version.
A slightly cleaner solution is to take the SQL from the script, add a manual migration, and change the contents of Up to simply:
public void Up()
{
Sql("...That SQL you extracted from the script...");
}
This will ensure other environments running this migration do so precisely the way you intended.
Testing this is a bit tricky so you can approach it this way:
Backup your db just in case.
Run the SQL. If it works properly, set the SQL aside.
Add the manual migration and wipe out everything in the Up() method. Leave it completely empty.
Run update-database -f
Now modify the Up() method by adding the Sql("..."); calling the SQL you set aside.
Now your db is up to date without running the SQL twice, and other environments get the results of that SQL.

Entity Framework Migrations - support for dynamic connection string

I can't make the migrations work for a specific scenario.
Our application uses two different models. The first is for the main database and there, the migration is working fine. The second model is for our customers databases which are specific for each customer (of course...) but all share the same model.
So, in the application (ASP.Net MVC 3), we identify the customer using the route and all customers are hosted in the same application. So, for each request we pass a key to our customer model dbContext constructor and with that key we recover the connection string through a simple helper method.
The application is working fine but not the migrations since I found no way to pass the key in the Package Manager Console.
I tried to create my own IDbConnectionFactory but it is not taken into account.
If I try an update-database command with the connection factory I get the following error which is normal since no key is passed but I can see that my connection factory is kicking in (EFCustomerModel.EFConnectionFactory):
PM> update-database -verbose
Using NuGet project 'EFCustomerModel'.
Using StartUp project 'PMEL.DatabaseSetup'.
System.ArgumentException: Format of the initialization string does not conform to specification starting at index 0.
at System.Data.Common.DbConnectionOptions.GetKeyValuePair(String connectionString, Int32 currentPosition, StringBuilder buffer, Boolean useOdbcRules, String& keyname, String& keyvalue)
at System.Data.Common.DbConnectionOptions.ParseInternal(Hashtable parsetable, String connectionString, Boolean buildChain, Hashtable synonyms, Boolean firstKey)
at System.Data.Common.DbConnectionOptions..ctor(String connectionString, Hashtable synonyms, Boolean useOdbcRules)
at System.Data.SqlClient.SqlConnectionString..ctor(String connectionString)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnectionOptions(String connectionString, DbConnectionOptions previous)
at System.Data.ProviderBase.DbConnectionFactory.GetConnectionPoolGroup(String connectionString, DbConnectionPoolGroupOptions poolOptions, DbConnectionOptions& userConnectionOptions)
at System.Data.SqlClient.SqlConnection.ConnectionString_Set(String value)
at System.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
at System.Data.SqlClient.SqlConnection..ctor(String connectionString)
**at EFCustomerModel.EFConnectionFactory.CreateConnection(String nameOrConnectionString) in C:\...\EFCustomerModel\EFConnectionFactory.vb:line 18**
at System.Data.Entity.Internal.LazyInternalConnection.Initialize()
at System.Data.Entity.Internal.LazyInternalConnection.get_Connection()
at System.Data.Entity.Internal.LazyInternalContext.get_Connection()
at System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType, DbProviderInfo modelProviderInfo, AppConfig config, DbConnectionInfo connectionInfo)
at System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.GetMigrator()
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.RunCore()
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
Format of the initialization string does not conform to specification starting at index 0.
But when I try to pass in my key using the -ConnectionString parameter, then my connection factory is ignored and I get the same error:
PM> update-database -verbose -ConnectionString:CC99999 -ConnectionProviderName:System.Data.SqlClient
Using NuGet project 'EFCustomerModel'.
Using StartUp project 'PMEL.DatabaseSetup'.
System.ArgumentException: Format of the initialization string does not conform to specification starting at index 0.
at System.Data.Common.DbConnectionOptions.GetKeyValuePair(String connectionString, Int32 currentPosition, StringBuilder buffer, Boolean useOdbcRules, String& keyname, String& keyvalue)
at System.Data.Common.DbConnectionOptions.ParseInternal(Hashtable parsetable, String connectionString, Boolean buildChain, Hashtable synonyms, Boolean firstKey)
at System.Data.Common.DbConnectionOptions..ctor(String connectionString, Hashtable synonyms, Boolean useOdbcRules)
at System.Data.SqlClient.SqlConnectionString..ctor(String connectionString)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnectionOptions(String connectionString, DbConnectionOptions previous)
at System.Data.ProviderBase.DbConnectionFactory.GetConnectionPoolGroup(String connectionString, DbConnectionPoolGroupOptions poolOptions, DbConnectionOptions& userConnectionOptions)
at System.Data.SqlClient.SqlConnection.ConnectionString_Set(String value)
at System.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
at System.Data.Entity.Internal.LazyInternalConnection.InitializeFromConnectionStringSetting(ConnectionStringSettings appConfigConnection)
at System.Data.Entity.Internal.LazyInternalConnection.Initialize()
at System.Data.Entity.Internal.LazyInternalConnection.get_Connection()
at System.Data.Entity.Internal.LazyInternalContext.get_Connection()
at System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType, DbProviderInfo modelProviderInfo, AppConfig config, DbConnectionInfo connectionInfo)
at System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType, DbConnectionInfo connectionInfo)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.GetMigrator()
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.RunCore()
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
Format of the initialization string does not conform to specification starting at index 0.
So, is this an unsupported scenario in the migrations or there is another way to pass in my key or maybe there is another way to generate my connection strings?
You should be able to pass a key to your custom connection factory with the -ConnectionStringName parameter. This parameter would be passed to the CreateConnection method.
Another possible solution would be to call DB migration from your code:
var configuration = new Configuration();
configuration.TargetDatabase = new DbConnectionInfo(
"Server=MyServer;Database=MyDatabase;Trusted_Connection=True;",
"System.Data.SqlClient");
var migrator = new DbMigrator(configuration);
migrator.Update();