繁体   English   中英

实体框架中出现意外行为

[英]Unexpected behavior in entity framework

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

首先,我创建了一个简单的DB表

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();

    }

}

底部的写行打印出“之前”,但我希望它打印出“之后”。 关于它的奇怪之处在于,如果我运行探查器,我会看到sql查询运行,如果我自己在管理工作室中运行查询,则返回“After”作为名称。 我正在运行SQL Server 2014。

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

更新:

它将转到FirstOrDefault行的数据库。 请参阅sql profiler附带的屏幕截图。

在此输入图像描述

所以我的问题是这样的:

1)如果是缓存,不应该不去DB吗? 这是EF中的一个错误吗?

2)如果要进入db并花费资源,不应该更新EF对象。

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

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

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

更新

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

至于为什么内存中的对象没有更新以反映数据库中的变化,我需要做一些研究来做更多的事情而不是推测。 那就是说,这是我的猜测:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM