Entity Framework Code First AddOrUpdate method insert Duplicate values

C#.NetEntity Framework-4

C# Problem Overview


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.

C# Solutions


Solution 1 - C#

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 - C#

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 - C#

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

Solution 4 - C#

This can also be caused if you're setting the Entity State incorrectly. I kept getting the following error when I'd run update-database..."Sequence contains more than one matching element."

For example, I had duplicate rows being created on each update-database command (which of course is not supposed to happen when seeding data), and then the next update-database command wouldn't work at all since it found more than one match (hence the sequence error saying I have more than one matching row). That's because I had overridden SaveChanges in my context file with a method call to ApplyStateChanges...

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

I was using ApplyStateChanges to ensure that when adding object graphs, Entity Framework knows explicitly whether the object is in an added or modified state. The entire explanation on how I'm using ApplyStateChanges can be found here.

And this works great (but the caveat!!)...if you're also seeding the database using CodeFirst migrations, then the above method will cause havoc for the AddOrUpdate() call within the Seed Method. So before anything else, just check your DBContext file and ensure you're not overriding SaveChanges in the way above, or you will end up getting duplicate data running the update-database command a second time, and then won't work at all the third time since there's more than one row for each matching item.

When it comes down to it, you don't need to configure the Id in AddOrUpdate()...that defeats the whole purpose of easy and initial database seeding. It works fine by something like:

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" },

just AS LONG as I'm not overriding the SaveChanges method in my context file with a call to ApplyStateChanges. Hope this helps.

Solution 5 - C#

These steps worked for me

  1. Delete all the rows in the table.
  2. Reset the incremental identity to 0. DBCC CHECKIDENT (yourtablename, RESEED, 0) (The primary keys specified in the Seed() must match those in the database table so that they do not duplicate.)
  3. Specify the primary keys in the 'seed' method.
  4. Run the Seed() method several times and you check if they duplicated.

Solution 6 - C#

I have found that AddOrUpdate works fine with fields that are not ID's. If this works for you: context.Halls.AddOrUpdate(h => h.Name, hall1, hall2, hall3)

You may want to use Hall names like 'French_test_abc_100', 'German_test_abc_100' etc.

That stops hard coded test data messing things up when you are testing your app.

Solution 7 - C#

If object(hall)'s id is 0, it is a insertion. I think you need to double check the id field of your hall objects

Solution 8 - C#

Is your ID field an Identity field? I was running into this same issue. When I removed the Identity status from my ID field and set the IDs going into the database, that resolved the issue.

That worked for me, since these were look-up tables and shouldn't have been identity fields, anyway.

Solution 9 - C#

I think it's likely that you need to back out existing database migrations (i.e. start your database from scratch) with something like Update-Database TargetMigration:0 followed by Update-Database.

As it is, you're not dropping the existing table or values, you're just add/updating those values. That needs to happen in order to get your desired result.

Solution 10 - C#

I used the ID field as Identity/Key and add attributes not to assign Ids by the server. This solved the problem for me.

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

    public string Name [get; set;}
 }

Solution 11 - C#

Just to Ciaren's answer, the below code of resetting the context on ModelCreating, helped me resolve similar issues. Make sure change "ApplicationContext" to your DbContext name.

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

Solution 12 - C#

I found out that for this to work, the identity position should be 0 when the seed first run. You can reset it using:

DBCC CHECKIDENT (tableName, RESEED, 0)

Solution 13 - C#

You could have also done this:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionY.YanavichusView Question on Stackoverflow
Solution 1 - C#Ciarán BruenView Answer on Stackoverflow
Solution 2 - C#Anthony NicholsView Answer on Stackoverflow
Solution 3 - C#Y.YanavichusView Answer on Stackoverflow
Solution 4 - C#firecapeView Answer on Stackoverflow
Solution 5 - C#franciscorodeView Answer on Stackoverflow
Solution 6 - C#DarynView Answer on Stackoverflow
Solution 7 - C#weeyoungView Answer on Stackoverflow
Solution 8 - C#JasonView Answer on Stackoverflow
Solution 9 - C#Harvey PowersView Answer on Stackoverflow
Solution 10 - C#GuntarsView Answer on Stackoverflow
Solution 11 - C#Riyaz HameedView Answer on Stackoverflow
Solution 12 - C#Brain BalakaView Answer on Stackoverflow
Solution 13 - C#Charles OwenView Answer on Stackoverflow