gpt4 book ai didi

c# - Entity Framework 中的意外行为

转载 作者:太空狗 更新时间:2023-10-29 23:07:14 25 4
gpt4 key购买 nike

我遇到了我认为 Entity Framework 的一个非常奇怪的情况。基本上,如果我直接使用 sql 命令更新一行,当我通过 linq 检索该行时,它没有更新的信息。请参阅以下示例以获取更多信息。

首先我创建了一个简单的数据库表

CREATE TABLE dbo.Foo (
Id int NOT NULL PRIMARY KEY IDENTITY(1,1),
Name varchar(50) NULL
)

然后我创建了一个控制台应用程序来向数据库添加一个对象,使用 sql 命令更新它,然后检索刚刚创建的对象。在这里:

public class FooContext : DbContext
{

public FooContext() : base("FooConnectionString")
{

}

public IDbSet<Foo> Foo { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Foo>().ToTable("Foo");
base.OnModelCreating(modelBuilder);
}

}

public class Foo
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}

public class Program
{
static void Main(string[] args)
{

//setup the context
var context = new FooContext();

//add the row
var foo = new Foo()
{
Name = "Before"
};
context.Foo.Add(foo);
context.SaveChanges();

//update the name
context.Database.ExecuteSqlCommand("UPDATE Foo Set Name = 'After' WHERE Id = " + foo.Id);

//get the new foo
var newFoo = context.Foo.FirstOrDefault(x => x.Id == foo.Id);

//I would expect the name to be 'After' but it is 'Before'
Console.WriteLine(string.Format("The new name is: {0}", newFoo.Name));
Console.ReadLine();

}

}

底部的写入行打印出“之前”,但我希望它打印出“之后”。奇怪的是,如果我运行探查器,我会看到运行的 sql 查询,如果我自己在 management studio 中运行查询,它会返回“After”作为名称。我正在运行 sql server 2014。

有人可以帮我理解这里发生了什么吗?

更新:

它将转到 FirstOrDefault 行上的数据库。请参阅附带的 sql 事件探查器屏幕截图。

enter image description here

所以我的问题真的是这样的:

1) 如果它是缓存,它不应该去数据库吗?这是 EF 中的错误吗?

2) 如果它要去数据库并消耗资源,EF 不应该更新对象。

最佳答案

FooContext 包括更改跟踪和缓存,因此从您的查询返回的内存中对象与您之前添加的实例相同。调用 SaveChanges() 确实会清除上下文,而 FooContext 并不知道数据库中在它下面发生的更改。

这通常是一件好事 -- 不必为每个操作都进行昂贵的数据库调用。

在您的示例中,尝试从新的 FooContext 进行相同的查询,您应该会看到“After”。

更新

回答您更新后的问题,是的,您是对的。我错过了您之前使用的 FirstOrDefault()。如果您使用的是 context.Find(foo.Id),就像我错误地假设的那样,那么就没有查询。

至于为什么内存中的对象没有更新以反射(reflect)数据库中的变化,我需要做一些研究才能做更多的推测。也就是说,这是我的推测:

  • 数据库上下文的一个实例不能返回同一实体的多个实例。在一个工作单元中,我们必须能够依赖上下文返回实体的相同实例。否则,我们可能会通过不同的条件进行查询并得到 3 个表示相同概念实体的对象。那时,上下文如何处理其中任何一个的变化?如果其中两个的名称更改为不同的值,然后调用 SaveChanges() - 会发生什么?
  • 鉴于上下文最多跟踪每个实体的单个实例,为什么 EF 不能仅在执行查询时更新该实体?如果存在未决的内存更改,EF 甚至可以放弃该更改,因为它知道这些更改。
    • 我认为部分答案是区分大型实体和大型结果集中的所有列会导致性能过高。
    • 我认为答案的更大一部分是它执行一个简单的 SELECT 语句不应该有可能在整个系统中引起副作用。实体可能会根据某些属性的值进行分组或循环,并在不确定的时间更改该属性的值,因为 SELECT 查询的结果是非常不合理的。

关于c# - Entity Framework 中的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25859467/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com