Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net EF 4.3.1迁移异常-AlterColumn defaultValueSql为不同的表创建相同的默认约束名称_.net_Entity Framework_Entity Framework 4.3_Entity Framework Migrations - Fatal编程技术网

.net EF 4.3.1迁移异常-AlterColumn defaultValueSql为不同的表创建相同的默认约束名称

.net EF 4.3.1迁移异常-AlterColumn defaultValueSql为不同的表创建相同的默认约束名称,.net,entity-framework,entity-framework-4.3,entity-framework-migrations,.net,Entity Framework,Entity Framework 4.3,Entity Framework Migrations,我有一个使用OOB数据库初始值设定项创建的DB,我首先使用EF4.3.1中的代码 我想利用Add-Migration cmdlet上新的“IgnoreChanges”标志,以便可以更改一些列并添加默认SQL值。本质上,我的一些实体有一个名为DateLastUpdated的列,我想将其默认设置为sql表达式GETDATE() 我使用“add migration InitialMigration-ignorechanges”创建了InitialMigration,然后将以下内容添加到Up()和Dow

我有一个使用OOB数据库初始值设定项创建的DB,我首先使用EF4.3.1中的代码

我想利用Add-Migration cmdlet上新的“IgnoreChanges”标志,以便可以更改一些列并添加默认SQL值。本质上,我的一些实体有一个名为DateLastUpdated的列,我想将其默认设置为sql表达式GETDATE()

我使用“add migration InitialMigration-ignorechanges”创建了InitialMigration,然后将以下内容添加到Up()和Down()

然后我尝试运行“updatedatabase-verbose”,但我看到它试图在数据库上创建相同的命名默认约束,SQL抛出一个异常:

Applying explicit migrations: [201203221856095_InitialMigration].
Applying explicit migration: 201203221856095_InitialMigration.
ALTER TABLE [CustomerLocations] ADD CONSTRAINT DF_DateLastUpdated DEFAULT GETDATE() FOR [DateLastUpdated]
ALTER TABLE [CustomerLocations] ALTER COLUMN [DateLastUpdated] [datetime]
ALTER TABLE [UserReportTemplates] ADD CONSTRAINT DF_DateLastUpdated DEFAULT GETDATE() FOR [DateLastUpdated]
System.Data.SqlClient.SqlException (0x80131904): There is already an object named 'DF_DateLastUpdated' in the database.
Could not create constraint. See previous errors.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
   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)
   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.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()
There is already an object named 'DF_DateLastUpdated' in the database.
Could not create constraint. See previous errors.

看起来EF正在创建默认约束,方法是将“DF_3;”与列的名称一起添加,但不使用表的名称,以使其对表唯一。这是一个已知的错误,还是我在这里做错了什么?

这似乎是一个已知的错误:

安德鲁·彼得斯(Andrew J Peters)微软公司(MSFT)回答说:

谢谢你的报道。RTM将解决该问题

一种可能的解决方法是首先使列为null,这 将阻止迁移生成额外的默认约束。 创建列后,可以将其更改回 不可为空

但在EF 4.3.1中,它并没有被确定。以下是资料来源的相关部分:

// Type: System.Data.Entity.Migrations.Sql.SqlServerMigrationSqlGenerator
// Assembly: EntityFramework, Version=4.3.1.0, 
// Culture=neutral, PublicKeyToken=b77a5c561934e089
namespace System.Data.Entity.Migrations.Sql
{
  public class SqlServerMigrationSqlGenerator : MigrationSqlGenerator
  {
     protected virtual void Generate(AlterColumnOperation alterColumnOperation)
     {
      //...
      writer.Write("ALTER TABLE ");
      writer.Write(this.Name(alterColumnOperation.Table));
      writer.Write(" ADD CONSTRAINT DF_");
      writer.Write(column.Name);
      writer.Write(" DEFAULT ");
      //...
因此EF不会试图使约束名称唯一

您应该尝试解决方法并将其报告为bug

编辑: 我刚刚意识到上面提到的
Generate
方法是
virtual
,因此在最坏的情况下,您可以从
SqlServerMigrationSqlGenerator
继承并修复SQL生成,并将其设置为Configuration.cs中的SQL生成器:

public Configuration()
{
    AutomaticMigrationsEnabled = true;
    SetSqlGenerator("System.Data.SqlClient", 
        new MyFixedSqlServerMigrationSqlGenerator());
}
编辑2:

我认为最好的办法是,在它恢复到原始SQL之前:

public override void Up()
{
    Sql(@"ALTER TABLE [CustomerLocations] ADD CONSTRAINT 
        DF_CustomerLocations_DateLastUpdated 
        DEFAULT GETDATE() FOR [DateLastUpdated]");
    Sql(@"ALTER TABLE [CustomerLocations] ALTER COLUMN 
        [DateLastUpdated] [datetime]");
    //...
}

好的,根据nemesv的回答(已接受),以下是我现在如何解决问题,直到正式发布解决方案:

internal class MyFixedSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
    protected override void Generate(AlterColumnOperation alterColumnOperation)
    {
        if (alterColumnOperation == null)
            throw new ApplicationException("alterColumnOperation != null");

        ColumnModel column = alterColumnOperation.Column;
        if ((column.DefaultValue != null) || !string.IsNullOrWhiteSpace(column.DefaultValueSql))
        {
            using (IndentedTextWriter writer = Writer())
            {
                writer.Write("ALTER TABLE ");
                writer.Write(this.Name(alterColumnOperation.Table));
                writer.Write(" ADD CONSTRAINT DF_");
                writer.Write(alterColumnOperation.Table + "_"); //   <== THIS IS THE LINE THAT FIXES THE PROBLEM
                writer.Write(column.Name);
                writer.Write(" DEFAULT ");
                writer.Write(column.DefaultValue != null ? base.Generate(column.DefaultValue) : column.DefaultValueSql);
                writer.Write(" FOR ");
                writer.Write(this.Quote(column.Name));
                this.Statement(writer);
            }
        }
        using (IndentedTextWriter writer2 = Writer())
        {
            writer2.Write("ALTER TABLE ");
            writer2.Write(this.Name(alterColumnOperation.Table));
            writer2.Write(" ALTER COLUMN ");
            writer2.Write(this.Quote(column.Name));
            writer2.Write(" ");
            writer2.Write(this.BuildColumnType(column));
            if (column.IsNullable.HasValue && !column.IsNullable.Value)
            {
                writer2.Write(" NOT NULL");
            }
            this.Statement(writer2);
        }
    }
}


internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;

        SetSqlGenerator("System.Data.SqlClient", new MyFixedSqlServerMigrationSqlGenerator());
    }
    ...
}
内部类MyFixedSqlServerMigrationSqlGenerator:SqlServerMigrationSqlGenerator
{
受保护的覆盖无效生成(AlterColumnOperation AlterColumnOperation)
{
if(alterColumnOperation==null)
抛出新的ApplicationException(“alterColumnOperation!=null”);
ColumnModel column=alterColumnOperation.column;
if((column.DefaultValue!=null)| |!string.IsNullOrWhiteSpace(column.DefaultValueSql))
{
使用(IndentedTextWriter=writer())
{
writer.Write(“更改表”);
writer.Write(this.Name(alterColumnOperation.Table));
writer.Write(“添加约束DF_”);

Write(alterColumnOperation.Table+“”)/此解决方案在EF 6.1.3中进行了测试。很可能适用于以前的版本

您可以从System.Data.Entity.SqlServer命名空间实现从SqlServerMigrationSqlGenerator派生的自定义sql生成器类:

using System.Data.Entity.Migrations.Model;
using System.Data.Entity.SqlServer;

namespace System.Data.Entity.Migrations.Sql{
    internal class FixedSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator {
        protected override void Generate(AlterColumnOperation alterColumnOperation){
            ColumnModel column = alterColumnOperation.Column;
            var sql = String.Format(@"DECLARE @ConstraintName varchar(1000);
            DECLARE @sql varchar(1000);
            SELECT @ConstraintName = name   FROM sys.default_constraints
                WHERE parent_object_id = object_id('{0}')
                AND col_name(parent_object_id, parent_column_id) = '{1}';
            IF(@ConstraintName is NOT Null)
                BEGIN
                set @sql='ALTER TABLE {0} DROP CONSTRAINT [' + @ConstraintName+ ']';
            exec(@sql);
            END", alterColumnOperation.Table, column.Name);
                this.Statement(sql);
            base.Generate(alterColumnOperation);
            return;
        }
        protected override void Generate(DropColumnOperation dropColumnOperation){
            var sql = String.Format(@"DECLARE @SQL varchar(1000)
                SET @SQL='ALTER TABLE {0} DROP CONSTRAINT [' + (SELECT name
                    FROM sys.default_constraints
                    WHERE parent_object_id = object_id('{0}')
                    AND col_name(parent_object_id, parent_column_id) = '{1}') + ']';
            PRINT @SQL;
                EXEC(@SQL); ", dropColumnOperation.Table, dropColumnOperation.Name);

                    this.Statement(sql);
            base.Generate(dropColumnOperation);
        }
    }
}
并设置此配置:

internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;

        SetSqlGenerator("System.Data.SqlClient", new FixedSqlServerMigrationSqlGenerator ());
    }
    ...
}
内部密封类配置:dbmigtorinsconfiguration
{
公共配置()
{
AutomaticMiggerationsEnabled=真;
SetSqlGenerator(“System.Data.SqlClient”,新的FixedSqlServerMigrationSqlGenerator());
}
...
}

你从哪里获得EF的代码?我使用的是Reflector,但该生成方法的一部分可能使用了大量lambda、funcs/actions和匿名内容,因此Reflector没有给我一个好的版本来复制和修改。我在Resharper中使用了内置反编译程序(你可以使用免费的Jetbrains反编译程序)Telerik的JustDecompile也生成了几乎相同的源代码。但两者都包含大量lambad:(因此它不能直接重用。@ThiagoSilva我认为最简单的方法是用原始SQL编写这种迁移,直到这个错误修复。我已经更新了我的答案。一年后,在EF5中仍然没有修复。现在似乎已经修复了。根据我遇到的问题,
alterColumnOpe,这些约束被命名为DF_tableName_columnNameration.Table
包含架构,导致约束的名称无效(如'DF_dbo.MyTable_MyColumn')。我使用此帮助器方法修复了它:
private string RemoveSchema(string name){return name.Split('.').Last();}
不知道是否更安全,但如果他们更改默认EF方法,而不是使用IndentedTextWriter…
块更改第二个
,您可以将默认值设置为
null
并让基方法完成子句的创建:
column.DefaultValue=null;column.DefaultValueSql=null;base.Generate(alterColumnOperation);
检查Elyas的答案。这是一个很好的解决方案
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;

        SetSqlGenerator("System.Data.SqlClient", new FixedSqlServerMigrationSqlGenerator ());
    }
    ...
}