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