使用EF5 Code First Migrations执行IDENTITY_INSERT

时间:2013-03-06 21:37:08

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

我有一个POCO,我试图通过Code First Migrations创建,然后播种数据。问题是我想在播种时将特定值插入标识列。

这是我的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我可以应用于模型来帮助解决这个问题?

4 个答案:

答案 0 :(得分:18)

如何通过属性/约定

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

    public Team Team { get; set; }
}

这是通过EntityTypeConfiguration

关闭Identity的方法
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);
    }

答案 1 :(得分:6)

如果有人仍然感到困惑。 。

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

我确实使用Aron的context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT myTable ON")属性实现将模型ID的DB生成属性设置为'None',但我仍然无法通过标识插入错误。我想我会在这里发布我的发现,以防其他人仍然遇到麻烦。

为了使它工作,我将种子方法的逻辑包装在SQL事务中,并使用.AddOrUpdate()在运行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 方法之前允许插入。这是我的Configuration.vb文件(使用Google API类型的表作为示例数据):

class Base{
public:
    Base(){
        cout << "Base::Base() called\n";
    }

    virtual ~Base(){}

    virtual void output(int x){
        cout << "Base::output(int x) called\n";
    }

    virtual void output(double x){
        cout << "Base::output(double x) called\n";
    }

    virtual void output(char x){
        cout << "Base::output(char x) called\n";
    }

    virtual void output(string x){
        cout << "Base::ouput(string x) called\n";
    }
};


class Derived : public Base{
public:
    Derived():Base(){
        cout << "Derived::Derived() called\n";
    }

    virtual ~Derived(){}

    virtual void output(string x){
        cout << "Derived::ouput(string x) called\n";
    }

};

答案 2 :(得分:3)

在研究之后,看起来如果密钥先前已创建,然后在迁移中添加[DatabaseGenerated(DatabaseGeneratedOption.None)]它实际上不会按照您的意图执行,您可以通过转到数据库资源管理器表来检查 - &GT;键 - &gt; PK - &gt;修改并查看身份规范设置为是而不是否。

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

答案 3 :(得分:0)

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

示例:

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