Home > Net >  What is the logic behind EF SaveChanges Method?
What is the logic behind EF SaveChanges Method?

Time:01-01

When I insert a new Item in a DBSet like:

var newItemAdded = MyDBSet.Add(itemToAdd);

Then I save the changes in the DB like:

MyContext.SaveChanges();

My variable newItemAdded has been updated with the new Id auto generated by the DB.

I went to EF Core Github to see the logic, but with the big amount of files in the repository, I'm not sure to understand the logic behind.

My concern is more about how the SaveChanges executed after the insert could update newItemAdded. EF does not seem to use ref.

Maybe someone already know how does it work?

Thanks

CodePudding user response:

This works, without ref:

class Person{
  int Id {get;set;} = -1; 
  string Name {get;set;}
}

...

void SaveChanges(Person per){     //no ref here
  //simulate saving to DB
  per.Id = new Random().Next();
}

...

var p = new Person{ Name = "John"; }
Console.WriteLine(p.Id); //prints -1;
SaveChanges(p);
Console.WriteLine(p.Id); //prints some random number

We never needed ref to make sure that the Id of the person set inside SaveChanges survived and was seen by p after SaveChanges was done.

Conceptually this is what happens in memory when the SaveChanges code above is called:

p --> [ John, -1 ]                 //var p = new Person{Name = "John"}
p --> [ John, -1 ] <-- per         //SaveChanges(p), establishes another variable per, pointing at the same in memory data
p --> [ John, 23 ] <-- per       //per.Id = random number
p --> [ John, 23 ]               //method exits, variable per goes away. p survives and sees changed data

ref is a mechanism that would allow SaveChanges to swap the passed in Person out for a whole new Person. If you had a SaveChanges like:

void SaveChanges(Person per){
  per = new Person{ Name = "Jane", Id = 234 }
}

Then the objects in memory steps would look like:

p --> [ John, -1 ]                             //var p = new Person{Name = "John"}
p --> [ John, -1 ] <-- per                     //SaveChanges(p), establishes another reference called per, pointing at the same in-memory data
p --> [ John, -1 ]     per --> [Sarah, 23]     //per is reassigned to a new Person created elsewhere in memory
p --> [ John, -1 ]                             //method exits, variable per goes away. Sarah is vaporized. John was never changed

Suppose we use ref:

void SaveChanges(ref Person per){
  per = new ...
}

ref means p and per are the same reference. There isn't an additional one made, which could be pointed somewhere else while p stayed pointing at John

Imagine that ref temporarily renamed p to per and thus the SaveChanges method doing per = new Person also affects p. It could be thought of as like:

p ---------> [ John, -1 ]                    //var p = new Person{Name = "John"}
per was p -> [ John, -1 ]                    //SaveChanges(p), establishes another variable per, pointing at the same in memory data
per was p -> [ Sarah, 23]                    //per = new Person..., John is lost here
p ---------> [ Sarah, 23]                    //method exits, variable per goes away. p is the only remaining reference, 

When EF core saves the changes, it doesn't wholesale replace the entity you passed in with a new entity; it modifies some of the data inside the entity. It doesn't need ref for your code to see the changes it made

It doesn't even matter that EF is a two step process - you pass your entity into Add, EF stores it in an internal list, when it SaveChanges() it accesses the data via its own reference for it, but because there is only one data and both your variable and EF's list point to the same data, when EF changes the data your variable sees it, because it's the same data at the same memory location

  • Related