在数据库中已经存在一个被命名的对象。

144

从程序包管理器控制台更新数据库失败。

我使用了Entity Framework 6.x和Code First方法。

错误信息为"There is already an object named 'AboutUs' in the database."

我该如何解决这个问题?

internal sealed class Configuration 
    : DbMigrationsConfiguration<Jahan.Blog.Web.Mvc.Models.JahanBlogDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = false;
    }

    protected override void Seed(Jahan.Blog.Web.Mvc.Models.JahanBlogDbContext context)
    {

    }
}

我的 DbContext 是:

public class JahanBlogDbContext : IdentityDbContext<User, Role, int, UserLogin, UserRole, UserClaim>
{
    public JahanBlogDbContext()
        : base("name=JahanBlogDbConnectionString")
    {
        Database.SetInitializer(new DropCreateDatabaseIfModelChanges<JahanBlogDbContext>());
    }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Entity<Comment>().HasRequired(t => t.Article).WithMany(t => t.Comments).HasForeignKey(d => d.ArticleId).WillCascadeOnDelete(true);
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<User>().ToTable("User");
        modelBuilder.Entity<Role>().ToTable("Role");
        modelBuilder.Entity<UserRole>().ToTable("UserRole");
        modelBuilder.Entity<UserLogin>().ToTable("UserLogin");
        modelBuilder.Entity<UserClaim>().ToTable("UserClaim");
    }

    public virtual DbSet<Article> Articles { get; set; }
    public virtual DbSet<ArticleLike> ArticleLikes { get; set; }
    public virtual DbSet<ArticleTag> ArticleTags { get; set; }
    public virtual DbSet<AttachmentFile> AttachmentFiles { get; set; }
    public virtual DbSet<Comment> Comments { get; set; }
    public virtual DbSet<CommentLike> CommentLikes { get; set; }
    public virtual DbSet<CommentReply> CommentReplies { get; set; }
    public virtual DbSet<ContactUs> ContactUs { get; set; }
    public virtual DbSet<Project> Projects { get; set; }
    public virtual DbSet<ProjectState> ProjectStates { get; set; }
    public virtual DbSet<ProjectTag> ProjectTags { get; set; }
    public virtual DbSet<Rating> Ratings { get; set; }
    public virtual DbSet<Tag> Tags { get; set; }
    public virtual DbSet<AboutUs> AboutUs { get; set; }
}

包管理控制台:

PM> update-database -verbose -force
Using StartUp project 'Jahan.Blog.Web.Mvc'.
Using NuGet project 'Jahan.Blog.Web.Mvc'.
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Target database is: 'Jahan-Blog' (DataSource: (local), Provider: System.Data.SqlClient, Origin: Configuration).
No pending explicit migrations.
Applying automatic migration: 201410101740197_AutomaticMigration.
CREATE TABLE [dbo].[AboutUs] (
    [Id] [int] NOT NULL IDENTITY,
    [Description] [nvarchar](max),
    [IsActive] [bit] NOT NULL,
    [CreatedDate] [datetime],
    [ModifiedDate] [datetime],
    CONSTRAINT [PK_dbo.AboutUs] PRIMARY KEY ([Id])
)
System.Data.SqlClient.SqlException (0x80131904): There is already an object named 'AboutUs' in the database.
   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, Boolean asyncWrite)
   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.Infrastructure.Interception.DbCommandDispatcher.<NonQuery>b__0(DbCommand t, DbCommandInterceptionContext`1 c)
   at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand command, DbCommandInterceptionContext interceptionContext)
   at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteNonQuery()
   at System.Data.Entity.Migrations.DbMigrator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement, DbInterceptionContext interceptionContext)
   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.AutoMigrate(String migrationId, VersionedModel sourceModel, VersionedModel targetModel, Boolean downgrading)
   at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.AutoMigrate(String migrationId, VersionedModel sourceModel, VersionedModel 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.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)
ClientConnectionId:88b66414-8776-45cd-a211-e81b2711c94b
There is already an object named 'AboutUs' in the database.
PM> 

我该怎么做(映射到现有设计)? - x19
15
如果“精心设计的数据库”可以使用EF映射到对象模型中,那么EF也可以生成它。数据库迁移是一种强大的工具,可以使您的数据库部署更加容易。我不建议避免使用数据库迁移。否则,补丁脚本仍然是必需的。我建议正确使用数据库迁移。 - Ilya Palkin
31个回答

152

迁移过程中似乎存在问题,可在“程序包管理器控制台”中运行add-migration命令:

Add-Migration Initial -IgnoreChanges

进行一些更改,然后从“Initial”文件更新数据库:

Update-Database -verbose

编辑:-IgnoreChanges适用于EF6而非EF Core,以下是解决方法:https://dev59.com/qVcP5IYBdhLWcg3w39w-#43687656


11
这到底是做什么的?这样做是否允许新模型覆盖旧模型? - Travis Tubbs
1
我开始使用手动迁移,因为我的数据库中既有视图又有表。我曾尝试过使用自动迁移,但犯了错误,结果它试图从视图中创建表。在这种情况下,您的解决方案无效,我应该始终使用手动迁移。因此,在进行这些更改后,我必须撤消源代码控制中的更改,并从 _Migrations 表中删除“Initial”条目。 - arame3333
3
这让我进入了一个无限循环:包管理器控制台不允许我执行Add-Migration操作,因为它会出现错误“无法生成显式迁移,因为存在以下显式迁移待处理…”即InitialCreate。但是如果我不能成功运行Update-Database操作,除非有一些Initial -IgnoreChanges,那我应该怎么办呢? - East of Nowhere
10
Add-Migration:找不到与参数名称"IgnoreChanges"匹配的参数。 - Tzvi Gregory Kaidanov
3
@TravisTubbs,这忽略了您所做的更改并“伪造”了您的模型与迁移表同步的情况。 您仍然需要手动同步两者;在我的情况下,我删除了对模型所做的更改,执行了Add-Migration,在执行update-database之前从up/down方法中删除了内容-这使我返回到破坏性迁移之前的状态。 然后我实际上重新添加了更改,执行了add-migration和update-database,一切都同步了。 - Maverick Meerkat
显示剩余3条评论

89
也许您已经在项目中更改了命名空间!
您的数据库中有一个名为dbo.__MigrationHistory的表。该表有一个名为ContextKey的列。
此列的值基于您的命名空间。例如 "DataAccess.Migrations.Configuration"。
当您更改命名空间时,会导致具有不同命名空间的重复表名。
因此,在代码侧更改命名空间后,也要在数据库中更改此表的命名空间(对于所有行)。
例如,如果您将命名空间更改为EFDataAccess,则应将dbo.__MigrationHistoryContextKey列的值更改为"EFDataAccess.Migrations.Configuration"。
然后在代码侧的“工具”=>“程序包管理器控制台”,使用update-database命令。

除了在数据库中更改上下文值之外,还可以在您的代码中硬编码上下文值以使用旧命名空间值。方法是继承DbMigrationsConfiguration<YourDbContext>,在构造函数中将旧上下文值分配给ContextKey,继承自MigrateDatabaseToLatestVersion<YourDbContext,YourDbMigrationConfiguration>,并将该类留空。最后要做的是在静态构造函数中,在您的DbContext中调用Database.SetInitializer(new YourDbInitializer());

希望您的问题得到解决。


10
太棒了,我们正好遇到了这个问题! - Olivier ROMAND
4
实际上这是导致此错误的真正原因。EF 正在尝试创建数据库,因为它无法读取应用于数据库的迁移,原因是命名空间不同。 - yigitt
谢谢这个答案,对我帮助很大。正如Olivier ROMAND所说,我确实遇到了这个问题! - Enrique A. Pinelo Novelo
我之前并不知道这与此有关,但是即使删除了MigrationHistory表的记录,问题仍未得到解决...所以我放弃了所有的表格,让EF重新创建它们,这只是一个小应用程序,没什么大不了的...但这解决了我的问题。 - Niklas
没有这样的表。有一个名为 '__EFMigrationsHistory' 的表(使用 ef core),它没有那个列。 - emirhosseini
显示剩余5条评论

17
这个异常告诉你,有人已经向数据库中添加了一个名为“AboutUs”的对象。 AutomaticMigrationsEnabled = true; 可能会导致这种情况,因为在这种情况下,数据库版本不由您控制。为了避免不可预测的迁移并确保团队中的每个开发人员都使用相同的数据库结构,建议您将 AutomaticMigrationsEnabled = false;
如果你非常小心,并且是该项目上唯一的开发人员,自动迁移和编码迁移可以共存。 以下是来自Data Developer Center的自动 Code First 迁移文章的引用: 自动迁移允许您使用Code First Migrations,而无需为每个更改在项目中编写代码文件。但并非所有更改都可以自动应用,例如列重命名需要使用基于代码的迁移。
团队环境建议
您可以交替使用自动迁移和基于代码的迁移,但不推荐在团队开发场景中这样做。如果您是使用源代码控制的开发人员团队的一部分,则应仅使用纯自动迁移或纯基于代码的迁移。鉴于自动迁移的限制,我们建议在团队环境中使用基于代码的迁移。

17
在我的情况下,我的 EFMigrationsHistory 表被清空了(不知怎么地),当尝试运行 update-database 时,会得到如下错误信息:

数据库中已经存在一个名为 'AspNetUsers' 的对象

看到表被清空后,它再次运行初始迁移并尝试重新创建表是有道理的。
为解决这个问题,我向我的 EFMigrationsHistory表中添加了行。对于我知道数据库已经更新的每个迁移,我添加了一行。
每一行都有两列:MigrationIdProductVersion MigrationId 是您的迁移文件的名称。例如:20170628112345_Initial ProductVersion 是您正在运行的 EF 版本。您可以在包管理器控制台中键入 Get-Package 并查找您的 ef 包来找到它。
希望这对某些人有所帮助。

1
你是如何填充 Model 列的? - Ciaran Gallagher

8

在我的情况下,我重命名了包含“code-first”实体框架模型的程序集。虽然实际模式没有改变,但迁移表被称为

dbo.__MigrationHistory

这个列表包含了基于程序集名称已经执行的迁移。我已经更新了迁移表中的旧名称,以匹配新名称,然后迁移再次正常工作。


7
请确保您的解决方案启动项目在配置文件中有正确的连接字符串。或者在执行update-database命令时设置-StartUpProjectName参数。-StartUpProjectName参数指定要用于命名连接字符串的配置文件。如果省略,将使用指定项目的配置文件。
这里是ef-migration命令参考链接: http://coding.abel.nu/2012/03/ef-migrations-command-reference/

1
这个答案让我发现了我的错误,我只是将错误的项目设置为了启动项目。 - Martin Johansson
1
我之前也遇到了类似的问题,这个方法解决了我的问题。 - JordanTDN

5
我遇到了相同的问题,经过三个小时的奋斗,我找出了问题所在。
在我的情况下,在第一次迁移时,在up()方法中,默认代码想要创建已存在的表,因此我遇到了与您相同的错误。
为解决这个问题,只需删除那些代码并编写自己需要的代码。例如,我想要添加一列,所以我只需写入:
migrationBuilder.AddColumn<string>(
            name: "fieldName",
            table: "tableName",
            nullable: true);

看起来是个不错的答案,但你可能需要检查一下拼写。你也可以使用代码片段来明确最后一行是代码。如果需要帮助,请给我发消息。 - Mike Poole
谢谢。我该如何联系您? - arfa
3
添加代码片段的做法不错,@arfa。不需要按摩 :) 如果想私信我,请在评论区中输入“@”加上我的用户名。 - Mike Poole

3
从dbo_MigrationHistory表中删除行,或删除该表并运行。
update-database -verbose

它将逐个运行您项目中的所有迁移。

3
注意:不推荐使用此解决方案。但在某些情况下可以快速修复。
对我而言,在发布过程中,生产数据库中的 dbo._MigrationHistory 缺少迁移记录,而开发数据库中有所有迁移记录。
如果您确信生产数据库与开发数据库具有相同且最新的模式,则将所有迁移记录复制到生产数据库可能会解决该问题。
您可以仅使用VisualStudio来完成。
1. 打开“SQL Server对象资源管理器”面板> 在源(在我的情况下为dev db)数据库中右键单击dbo._MigrationHistory表> 单击“数据比较…”菜单。
2. 然后,数据比较向导弹出,请选择目标数据库(在我的情况下为生产数据库)并单击下一步。
3. 几秒钟后,它将显示一些仅存在于源数据库中的记录。 只需单击“更新目标”按钮即可。
4. 在浏览器中,单击刷新按钮,查看错误消息是否消失。
请注意,再次强调,这在复杂和严肃的项目中不被推荐。 只有在ASP.Net或EntityFramework学习过程中遇到问题时才使用此方法。

1
这对我很有效。不过,情况正好相反。我的生产数据库中所有记录都在__EFMigrationHistory表中,而开发数据库中的记录(除了最初的记录)不知何故缺失了。 - Jens Mander

2
在我的情况下,问题出现在 Seeder 中。我在其中调用了 _ctx.Database.EnsureCreated(),据我所知,更新数据库命令已成功执行,但然后 Seeder 尝试第二次创建数据库。
如何解决:
  1. 不要运行更新,只需启动应用程序并调用 EnsureCreated()。数据库将被创建/更新。
  2. 注释或删除 Seeder。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接