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

Y.Y*_*hus 58 .net c# entity-framework-4

我有简单的实体:

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

    public string Name [get; set;}
}
Run Code Online (Sandbox Code Playgroud)

然后在SeedAddOrUpdate用来填充表的方法中:

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
);
Run Code Online (Sandbox Code Playgroud)

然后我在Package Management Console中运行:

Add-Migration Current
Update-Database
Run Code Online (Sandbox Code Playgroud)

一切都很好:我在"Hall"表中有三行.但如果我Update-Database再次在Package Management Console中运行,我已经有五行:

Id  Name
1   French
2   Japaneese
3   German
4   French
5   Japanese
Run Code Online (Sandbox Code Playgroud)

为什么?我认为它应该是三行,而不是五行.我尝试使用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);
Run Code Online (Sandbox Code Playgroud)

另外,我通过nuget安装了最新的EntityFramework.

Cia*_*uen 63

好吧,我正用键盘敲打键盘一小时.如果表的Id字段是Identity字段,那么它将不起作用,因此对identifierExpression使用不同的字段.我使用了Name属性,还从new Hall {...}初始化程序中删除了Id字段.

这个对OPs代码的调整对我有用,所以我希望它可以帮助某人:

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 它的工作原理就像它的设计.如果将值插入表中,则SQL会在DB中分配下一个值.如果您不希望SQL/EF计算下一个要使用的密钥,那么您需要为您的实体关闭它.我已经发布了更远的答案,这解释了这一点. (4认同)

Ant*_*ols 12

我知道这是一个老问题,但正确的答案是,如果您自己设置id#并且想要使用AddOrUpdate,那么您需要告诉EF/SQL您不希望它生成ID#.

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

这样做的缺点是,当你插入一个新项目时,你需要设置它的Id,所以如果这是在运行时动态完成(而不是从种子数据),那么你需要计算下一个Id. Context.MyClasses.Max(c=>c.Id) + 1效果很好.


Y.Y*_*hus 9

此代码有效:

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 它可能有用,但它不正确.ID在服务器上生成.运行它,SQL将使用1和2作为前两个ID.然后删除这些行并再次运行它,Id = 1,将被忽略,SQL将在下次插入时使用ID = 3,4.或者在上面的代码中将Id更改为99,100.删除数据库,运行种子方法,它将不使用99,100,但SQL将使用1和2.此外,如果删除这些种子行,每个种子运行将再次插入相同的数据,因为ID将不匹配.使用Name作为唯一字段要好得多. (7认同)