我遇到了我认为实体框架非常奇怪的情况。基本上,如果我使用sql命令直接更新行,当我通过linq检索该行时,它没有更新的信息。有关详细信息,请参阅以下示例。
首先我创建了一个简单的数据库表
CREATE TABLE dbo.Foo (
Id int NOT NULL PRIMARY KEY IDENTITY(1,1),
Name varchar(50) NULL
)
然后我创建了一个控制台应用程序,用于向DB添加对象,使用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();
}
}
底部的写行打印出“之前”但是我希望它打印出“After”。关于它的奇怪之处在于,如果我运行探查器,我会看到sql查询运行,如果我自己在管理工作室中运行查询,则返回“After”作为名称。我正在运行sql server 2014。
有人可以帮我理解这里发生了什么吗?
更新:
它将转到FirstOrDefault行的数据库。请参阅sql profiler附带的屏幕截图。
所以我的问题是:
1)如果是缓存,不应该不去DB吗?这是EF中的错误吗?
2)如果要进入数据库并花费资源,则不应该更新对象。
答案 0 :(得分:6)
FooContext
包括更改跟踪和缓存,因此从查询返回的内存中对象与之前添加的实例相同。调用SaveChanges()
确实清除了上下文,FooContext
不知道数据库中发生的更改。
这通常是一件好事 - 不会为每个操作进行昂贵的数据库调用。
在您的示例中,尝试从新的FooContext
进行相同的查询,您应该看到&#34; After&#34;。
回答您的更新问题,是的,您是对的。在您使用FirstOrDefault()
之前我错过了。如果您使用的是context.Find(foo.Id)
,我错误地假设,那么就没有查询。
至于为什么内存中的对象没有更新以反映数据库中的变化,我需要做一些研究来做更多的事情而不是推测。那就是说,这是我的猜测:
SaveChanges()
该怎么办?