【问题标题】:Performing an IDENTITY_INSERT using EF5 Code First Migrations使用 EF5 Code First 迁移执行 IDENTITY_INSERT
【发布时间】:2017-07-19 22:07:11
【问题描述】:

我有一个 POCO,我正在尝试通过 Code First 迁移然后种子数据来创建它。问题是我想在播种时将特定值插入标识列。

这是我的 POCO

public class Result
{
    public long ResultId { get; set; }
    public long? TeamId { get; set; }

    public Team Team { get; set; }
}

这是我在 Configuration.cs 的 Seed 方法中的 AddOrUpdate 调用

context.Results.AddOrUpdate
    (
         r => r.ResultId,
         new Result { ResultId = 101, TeamId = null },
         new Result { ResultId = 201, TeamId = null }
    );

正如预期的那样,它不会插入 101 和 201 的值,而是插入 1 和 2。我可以将任何 DataAttributes 应用于模型来帮助解决这个问题吗?

【问题讨论】:

  • 您想完全禁用身份插入吗?或者只是为了你的种子方法?
  • 最初我只考虑播种...但如果 Code First 迁移有办法将 ID 列标识为主键但关闭 Identity,那也是可以接受的
  • 您在使用 EntityTypeConfiguration 吗?如果是这样,您可以使用 Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)。您可以在播种后在 OnModelCreating 和 this.Database.Initialize(force:true); 中关闭此选项;在构造函数中。

标签: c# asp.net-mvc entity-framework entity-framework-migrations


【解决方案1】:

如何通过属性/约定关闭身份

public class Result
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public long ResultId { get; set; }
    public long? TeamId { get; set; }

    public Team Team { get; set; }
}

这是您通过 EntityTypeConfiguration 关闭身份的方式

public class ResultMapper : EntityTypeConfiguration<Result>
{
    public ResultMapper()
    {
        HasKey(x => x.ResultId);
        Property(x => x.ResultId)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    }
}

或者你可以使用 OnModelCreating 重载

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Result>().Property(x => x.ResultId)
               .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    }

【讨论】:

  • 感谢@Aron,我使用您指定的属性方法成功插入了身份字段。
  • 如果 OP 需要 IDENTIY_INSERT,那是因为他们有一个身份列。您不能只取消该标识列来执行 IDENTITY_INSERT。然后,您需要再次迁移才能为该列再次打开 Identity。最好使用原始 SQL,而不是仅仅为某些插入更改数据库架构。
【解决方案2】:

万一有人仍然困惑。 . .

有关使 IDENTITY_INSERT 与 Code-First Migration Seed() 方法一起使用所需的其他信息,请参见下文

我确实使用 Aron 的 System.ComponentModel.DataAnnotations.Schema.DatabaseGenerated 属性实现将模型 ID 的 DB 生成属性设置为“无”,但我仍然无法克服身份插入错误。我想我会在这里发布我的发现,以防其他人仍然遇到问题。

为了让它工作,我将种子方法的逻辑包装在 SQL 事务中,并在运行 .AddOrUpdate() 方法之前使用context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT myTable ON") 允许插入。这是我的 Configuration.vb 文件(使用 Google API 类型的表作为我们的示例数据):

Imports System
Imports System.Data.Entity
Imports System.Data.Entity.Migrations
Imports System.Linq

Namespace Migrations

    Friend NotInheritable Class Configuration 
        Inherits DbMigrationsConfiguration(Of DAL.MyDbContext)

        Public Sub New()
            AutomaticMigrationsEnabled = False
            AutomaticMigrationDataLossAllowed = False
        End Sub

        Protected Overrides Sub Seed(context As DAL.MyDbContext)
            '  This method will be called after migrating to the latest version.

            Dim newContext As New MyDbContext(context.Database.Connection.ConnectionString)
            Using ts = newContext.Database.BeginTransaction()

                Try

                    ' Turn on identity insert before updating
                    newContext.Database.ExecuteSqlCommand("SET IDENTITY_INSERT GoogleApiTypeGroups ON")
                    ' Make sure the expected GoogleApiTypeGroups exist with the correct names and IDs.
                    newContext.GoogleApiTypeGroups.AddOrUpdate(
                        Function(x) x.Id,
                        New GoogleApiTypeGroup() With {.Id = 1, .name = "Google Cloud APIs"},
                        New GoogleApiTypeGroup() With {.Id = 2, .name = "YouTube APIs"},
                        New GoogleApiTypeGroup() With {.Id = 3, .name = "Google Maps APIs"},
                        New GoogleApiTypeGroup() With {.Id = 4, .name = "Advertising APIs"},
                        New GoogleApiTypeGroup() With {.Id = 5, .name = "Google Apps APIs"},
                        New GoogleApiTypeGroup() With {.Id = 6, .name = "Other popular APIs"},
                        New GoogleApiTypeGroup() With {.Id = 7, .name = "Mobile APIs"},
                        New GoogleApiTypeGroup() With {.Id = 8, .name = "Social APIs"})
                    ' Attempt to save the changes.
                    newContext.SaveChanges()
                    ' Turn off the identity insert setting when done.
                    newContext.Database.ExecuteSqlCommand("SET IDENTITY_INSERT GoogleApiTypeGroups OFF")

                    ' Turn on identity insert before updating
                    newContext.Database.ExecuteSqlCommand("SET IDENTITY_INSERT GoogleApiTypes ON")
                    ' Make sure the expected GoogleApiTypes exist with the correct names, IDs, and references to their corresponding GoogleApiTypeGroup.
                    newContext.GoogleApiTypes.AddOrUpdate(
                        Function(x) x.Id,
                        New GoogleApiType() With {.Id = 1, .name = "Google Maps JavaScript API", .GoogleApiTypeGroupId = 3})
                    ' Save the changes
                    newContext.SaveChanges()
                    ' Turn off the identity insert setting when done.
                    newContext.Database.ExecuteSqlCommand("SET IDENTITY_INSERT GoogleApiTypes ON")

                    ts.Commit()
                Catch ex As Exception
                    ts.Rollback()
                    Throw
                End Try
            End Using

        End Sub

    End Class

End Namespace

【讨论】:

    【解决方案3】:

    在对此进行研究之后,看起来如果之前创建了密钥,然后您在迁移中添加 [DatabaseGenerated(DatabaseGeneratedOption.None)] 它实际上不会按照您的意愿执行,您可以通过转到数据库资源管理器表来检查这一点-> Keys -> PK -> Modify and see the Identity Specification 设置为 Yes 而不是 No。

    如果是这种情况,请尝试向下迁移到该表不存在的位置,然后重新迁移回来。

    【讨论】:

    • 你真的让我很开心!谢谢!
    【解决方案4】:

    如果您使用 AutoMapper 并使用 for/foreach 模式,则必须在 for 循环中重新映射。

    例子:

    foreach (var item in Ids) {
        var page = Mapper.Map<Pages>(model);
        .
        .
        .
        .
        db.Pages.Add(page);
    }
    db.SaveChanges();
    

    【讨论】:

      猜你喜欢
      • 2013-01-28
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      • 2013-03-29
      • 1970-01-01
      • 2016-08-04
      • 2015-01-24
      相关资源
      最近更新 更多