Entity Framework Code First AddOrUpdate method insert Duplicate values

I have simple entity:

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

    public string Name [get; set;}
}

Then in the Seed method I use AddOrUpdate to populate table:

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
);

Then I run in the Package Management Console:

Add-Migration Current
Update-Database

It's all fine: I have three rows in the table "Hall". But if I run in the Package Management Console Update-Database again I have already five rows:

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

Why? I think it is should be three rows again, not five. I tried to use Id property instead of Name but it does not make the difference.

UPDATE:

This code produces the same result:

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);

Also I have the latest EntityFramework installed via nuget.


Solution 1:

Ok I was banging my face off the keyboard for an hour with this. If your table's Id field is an Identity field then it won't work so use a different one for identifierExpression. I used the Name property and also removed the Id field from the new Hall {...} initializer.

This tweak to the OPs code worked for me so I hope it helps someone:

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();
}

Solution 2:

I know this is an old question, but the right answer is that if you are setting the id # yourself and you want to use AddOrUpdate then you need to tell EF/SQL that you don't want it to generate the ID #.

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

The down side to this is that when you insert a new item you need to set it's Id, so if this is done dynamically at runtime (instead of from seed data) then you will need to calculate out the next Id. Context.MyClasses.Max(c=>c.Id) + 1 works well.

Solution 3:

This code works:

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();
}