实体框架代码优先AddOrUpdate方法插入重复的值实体框架代码优先AddOrUpdate方法插入

2019-05-13 10:38发布

我有简单的实体:

public class Hall
{
    [Key]
    public int Id {get; set;}

    public string Name [get; set;}
}

然后在Seed的方法我用AddOrUpdate填充表:

var hall1 = new Hall { Name = "French" };
var hall2 = new Hall { Name = "German" };
var hall3 = new Hall { Name = "Japanese" };

context.Halls.AddOrUpdate(
    h => h.Name,
    hall1,
    hall2,
    hall3
);

然后,我在包管理控制台运行:

Add-Migration Current
Update-Database

这是所有罚款:我有表中“霍尔”三行。 但是,如果我在包管理控制台运行Update-Database再次我已经五行:

Id  Name
1   French
2   Japaneese
3   German
4   French
5   Japanese

为什么? 我认为这是应该重新三人行,不是五个。 我试图用Id属性,而不是Name ,但它不赚取差价。

更新:

此代码产生相同的结果:

var hall1 = new Hall { Id = 1, Name = "French" };
var hall2 = new Hall { Id = 2, Name = "German" };
var hall3 = new Hall { Id = 3, Name = "Japanese" };

context.Halls.AddOrUpdate(
                h => h.Id,
                hall1);

context.Halls.AddOrUpdate(
                h => h.Id,
                hall2);

context.Halls.AddOrUpdate(
                h => h.Id,
                hall3);

我也有通过的NuGet安装了最新的EntityFramework。

Answer 1:

好吧,我撞了我的脸离开键盘与此一个小时。 如果您的表的ID字段是一个标识字段,那么它不会工作,所以使用不同的一个identifierExpression。 我用的是Name属性,也从取出的Id场new Hall {...}初始化。

这种调整对代码为我工作的有机磷农药,所以我希望它可以帮助别人:

protected override void Seed(HallContext context)
{
    context.Halls.AddOrUpdate(
        h => h.Name,   // Use Name (or some other unique field) instead of Id
        new Hall
        {
            Name = "Hall 1"
        },
        new Hall
        {
            Name = "Hall 2"
        });

    context.SaveChanges();
}


Answer 2:

此代码的工作:

public Configuration()
{
    AutomaticMigrationsEnabled = true;
}

protected override void Seed(HallContext context)
{
    context.Halls.AddOrUpdate(
        h => h.Id,
        new Hall
        {
            Id = 1,
            Name = "Hall 1"
        },
        new Hall
        {
            Id = 2,
            Name = "Hall 2"
        });

    context.SaveChanges();
}


Answer 3:

我知道这是一个老问题,但正确的答案是,如果您自行设置编号和您要使用AddOrUpdate,那么你需要告诉你不希望它生成编号EF / SQL。

modelBuilder.Entity<MyClass>().Property(p => p.Id)
    .HasDatabaseGeneratedOption(System.ComponentModel
    .DataAnnotations.Schema.DatabaseGeneratedOption.None); 

向下的一面的情况是,当你插入你需要设置一个新的项目的ID,因此,如果这是在运行时(而不是从种子数据)动态完成的,那么你将需要计算出下一个ID。 Context.MyClasses.Max(c=>c.Id) + 1工作良好。



Answer 4:

如果你错误地设置了实体状态这也可以引起。 我一直得到以下错误,当我跑更新数据库...“序列包含一个以上的匹配元素。”

例如,我对每个更新的数据库命令(这当然是不应该播数据时发生的),然后下一更新数据库命令将不会在所有的,因为它找到一个以上的匹配工作正在创建重复的行(因此序列错误说我有一个以上的匹配行)。 那是因为我已经覆盖的SaveChanges在我的上下文文件,一个方法调用ApplyStateChanges ...

public override int SaveChanges()
{
    this.ApplyStateChanges();
    return base.SaveChanges();
}

我用ApplyStateChanges确保添加对象图时,实体框架知道对象明确是否在添加或修改状态。 关于我如何使用ApplyStateChanges整个的解释可以发现在这里 。

而这个伟大的工程(但需要注意的!)......如果你也使用播种迁移CodeFirst数据库,那么上面的方法会造成严重破坏的AddOrUpdate()种子的方法中调用。 所以任何事情之前,请查看您的DbContext文件,并确保你不是在路上覆盖的SaveChanges以上,否则你会最终得到重复数据运行更新的数据库命令第二次,然后在所有的都不行第三次,因为有一个为每个匹配项不止一行。

当它发生的时候,你并不需要配置AddOrUpdate()来击败容易和初始数据库播种的整个目的的Id ...。 它工作正常,通过这样的:

context.Students.AddOrUpdate(
    p => p.StudentName,
    new Student { StudentName = "Bill Peters" },
    new Student { StudentName = "Jandra Nancy" },
    new Student { StudentName = "Rowan Miller" },
    new Student { StudentName = "James O'Dalley" },

只是,只要我不重写我的背景文件SaveChanges方法一起ApplyStateChanges通话。 希望这可以帮助。



Answer 5:

这为我工作

  1. 删除表中的所有行。
  2. 重置增量同一性为0 DBCC CHECKIDENT (yourtablename, RESEED, 0)在指定的主键Seed()必须使得它们不重复匹配在数据库中的表)。
  3. 在“种子”方法指定主密钥。
  4. 运行Seed()方法几次,你检查它们是否重复。


Answer 6:

我发现AddOrUpdate工作正常与不ID的领域。 如果这对你的作品: context.Halls.AddOrUpdate(h => h.Name, hall1, hall2, hall3)

您可能需要使用霍尔的名字,如“French_test_abc_100”,“German_test_abc_100”等。

这将停止硬编码的测试数据弄乱的东西了,当你正在测试您的应用程序。



Answer 7:

如果对象(大厅)的ID为0,它是一种插入。 我认为你需要仔细检查id字段的厅内对象



Answer 8:

是您的ID字段标识字段? 我也陷入了同样的问题。 当我删除从我的ID字段中的身份地位,并设置标识进入数据库,即解决了问题。

这为我工作,因为这些是查找表,不应该是标识字段,反正。



Answer 9:

我认为这是可能的,你需要取消现有的数据库迁移(即从头开始你的数据库)的东西,如“更新,数据库TargetMigration:0”后跟“更新-数据库”。

正因为如此,你不会放弃现有的表或值,你只需要添加/更新这些值。 需要为了得到你想要的结果发生。

以下是EF迁移一个很好的参考: http://elegantcode.com/2012/04/12/entity-framework-migrations-tips/



Answer 10:

我使用的ID字段作为身份/ Key和添加属性不是由服务器分配的ID。 这解决了这个问题对我来说。

public class Hall
{
    [Key]
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Id {get; set;}

    public string Name [get; set;}
 }


Answer 11:

只是为了Ciaren的答案,重新上ModelCreating上下文下面的代码,帮我解决类似的问题。 确保变革“的ApplicationContext”你的DbContext的名字。

 public class ApplicationContext : DbContext, IDbContext { public ApplicationContext() : base("ApplicationContext") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); Database.SetInitializer<ApplicationContext>(null); base.OnModelCreating(modelBuilder); } } 



Answer 12:

我发现这个工作,身份位置应该是0,当种子首轮。 您可以使用重置:

DBCC CHECKIDENT (tableName, RESEED, 0)


Answer 13:

你可能也做到了这一点:

 context.Halls.AddOrUpdate(new Hall[]{hall1,hall2, hall3});


文章来源: Entity Framework Code First AddOrUpdate method insert Duplicate values