Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SaveChanges() is saving Unchanged records

I don't know if I'm missing something... anyway:

image 1

You can see, for example, that the object with the property 'HomeTeam' = ' Forest Green Rovers' has the state = 'Unchanged'. Anyway all entities are 'unchanged' in my case. So, if I'm correct, the saveChanges shouldn't try to insert those in my table but that's what it's happening:

image 2

The primary key has been violated, but EF shouldn't have tried to add this record (the one with the property HomeTeam = 'Forest Green Rovers') since it's 'Unchanged', right?

Why is EF doing that?

The entity:

{
using System;
using System.Collections.Generic;

public partial class MatchInfo
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public MatchInfo()
    {
        this.Sport = "Soccer";
        this.OddsInfoes1X2 = new HashSet<OddsInfo1X2>();
        this.Odds1X2Movements = new HashSet<OddsMovement>();
        this.OddsInfoOverUnders = new HashSet<OddsInfoOverUnder>();
        this.OddsMovementOverUnders = new HashSet<OddsMovementOverUnder>();
        this.HistoryResults = new HashSet<HistoryResult>();
    }

    public string League { get; set; }
    public System.DateTime Date { get; set; }
    public string HomeTeam { get; set; }
    public string AwayTeam { get; set; }
    public string FinalScore { get; set; }
    public string Sport { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<OddsInfo1X2> OddsInfoes1X2 { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<OddsMovement> Odds1X2Movements { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<OddsInfoOverUnder> OddsInfoOverUnders { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<OddsMovementOverUnder> OddsMovementOverUnders { get; set; }
    public virtual TeamsStatFinal TeamsStatFinal { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<HistoryResult> HistoryResults { get; set; }
}

}

More Info:

foreach (something){
     /*iterating on a web page and where I build the object oMatchInfo */
     if (oMatchInfo != null)
     {
          oMatchInfoTemp = (from m in context.MatchInfoes where m.HomeTeam == oMatchInfo.HomeTeam && m.AwayTeam == oMatchInfo.AwayTeam && m.Date == oMatchInfo.Date select m).FirstOrDefault<MatchInfo>();
          if (oMatchInfoTemp == null)
          {
              context.MatchInfoes.Add(oMatchInfo);
          }
          else
          {                                         
              context.OddsInfoes1X2.AddRange(oMatchInfo.OddsInfoes1X2);
          }
     }

}
/* here there is the context.saveChanges() - the context is the same */

ops. I have found my error and it's really stupid :-( in a related function inside the for there was some uncommented code where I was adding entities without checking the PK constraints. The state 'Unchanged' (first image) confused me and I have kept focusing on that... Sorry :-)

like image 208
Massimo Avatar asked Sep 14 '17 14:09

Massimo


People also ask

How does DB SaveChanges work?

Basically the db. SaveChanges() method is used by Entity Framework to save current changes to the database and ModelState represents validation errors when e.g. the model is not valid.

What is SaveChanges method?

SaveChanges() Saves all changes made in this context to the database. This method will automatically call DetectChanges() to discover any changes to entity instances before saving to the underlying database.

What does Dbcontext SaveChanges return?

Returns. The number of state entries written to the underlying database. This can include state entries for entities and/or relationships.

How do I speed up Entity Framework SaveChanges?

Turn off change tracking before you perform your inserts. This will improve your performance significantly (magnitudes of order). Putting SaveChanges() outside your loop will help as well, but turning off change tracking will help even more.


2 Answers

If you want to add entities to the context that are not new entities (the PK already exists in the database) then you need to Attach the entity rather than Add it.

More details here https://msdn.microsoft.com/en-us/library/jj592676(v=vs.113).aspx

To elaborate, look through the context contents carefully. You will find an entity that has the Added state.

like image 98
Gusdor Avatar answered Sep 28 '22 00:09

Gusdor


You're adding an existing entry to the database.

if (oMatchInfo != null)
{
    oMatchInfoTemp = (from m in context.MatchInfoes where m.HomeTeam == 
    oMatchInfo.HomeTeam && m.AwayTeam == oMatchInfo.AwayTeam && m.Date == 
    oMatchInfo.Date select m).FirstOrDefault<MatchInfo>();

    if (oMatchInfoTemp == null)
    {
        context.MatchInfoes.Add(oMatchInfo);
    }
    else
    {                                         
        context.OddsInfoes1X2.AddRange(oMatchInfo.OddsInfoes1X2);
    }
}

This way you're adding a model that has an ID which matches the entry in the database, therefore your database is giving the cannot insert duplicate key error.

like image 44
Baksteen Avatar answered Sep 28 '22 00:09

Baksteen