【问题标题】:What is the logic behind EF SaveChanges Method?EF SaveChanges 方法背后的逻辑是什么?
【发布时间】:2021-12-31 19:21:37
【问题描述】:

当我在 DBSet 中插入一个新项目时:

var newItemAdded = MyDBSet.Add(itemToAdd);

然后我将更改保存在数据库中,例如:

MyContext.SaveChanges();

我的变量 newItemAdded 已使用数据库自​​动生成的新 ID 进行了更新。

我去EF Core Github看逻辑,但是仓库里的文件很多,我不确定背后的逻辑。

我更关心的是插入后执行的 SaveChanges 如何更新 newItemAdded。 EF 似乎没有使用 ref

也许有人已经知道它是如何工作的?

谢谢

【问题讨论】:

  • 还有什么要解释的? EF 知道哪个属性是自动生成的键,MySQL 允许检索生成的 ID(可能是 SELECT LAST_INSERT_ID() .. 最近没看过),EF 将值返回..
  • 另外,我不保证你会在 efcore repo 中找到答案;您可能必须查看您正在使用的 MySQL 提供程序的来源(并且有一些) - 检索生成的 ID 将是数据库特定的事情(在 SQLS、MySQL 和 Oracle 中肯定不同),这意味着它将由提供者来做。最简单的方法可能是在上下文执行其工作时打开每个 SQL 运行的日志记录,然后查看它运行的内容..
  • 我不明白的是,通常当 am 对象在方法之外更新时,这是因为我们返回了一个 ref,所以这个引用的对象将被更新,而不是这种情况
  • 你完全误解了refref 与修改某些对象实例的数据内容内容无关; ref 允许一个方法在某个方法之外重新分配一个变量,以便该变量指向一个全新的对象。绝对不需要更改,例如传递给方法的人的名称...
  • 感谢您的解释,但 EF 无论如何都不使用 ref。但是对象 newItemAdded 在 savechanges 之后仍然会更新。如何重现?

标签: c# entity-framework entity-framework-core


【解决方案1】:

这工作,没有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

我们从来不需要ref 来确保在SaveChanges 中设置的人的ID 仍然存在并且在SaveChanges 完成后被p 看到。

从概念上讲,这是调用上述 SaveChanges 代码时在内存中发生的情况:

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 是一种允许 SaveChanges 将传入的 Person 交换为整个 new Person 的机制。如果您有类似的 SaveChanges:

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

那么内存步骤中的对象将如下所示:

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

假设我们使用 ref:

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

ref 表示pper 是同一个引用。没有制作额外的,可以指向其他地方,而p 一直指向约翰

想象一下,ref 暂时将p 重命名为per,因此执行per = new Person 的SaveChanges 方法也会影响p。可以这样想:

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, 

当 EF 核心保存更改时,它不会将您传入的实体全部替换为新实体;它修改了实体内部的一些数据。它不需要ref 让您的代码看到它所做的更改

EF 是一个两步过程甚至都没有关系——你将你的实体传递给 Add,EF 将它存储在一个内部列表中,当它 SaveChanges() 时它通过它自己的引用访问数据,但是因为只有一个数据,并且您的变量和 EF 的列表都指向相同的数据,当 EF 更改数据时,您的变量会看到它,因为它是相同内存位置的相同数据

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-25
    • 1970-01-01
    • 1970-01-01
    • 2014-05-06
    • 2017-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多