C# EF 6.0 where条款后的不正确项目

C# EF 6.0 where条款后的不正确项目,c#,entity-framework,C#,Entity Framework,在使用EF(FirstOrDefault)修改一个值并在另一个集合中使用Where子句请求相同的项之后,我对EF 6.0有一个问题 例如,假设类Foo具有3个属性:Id、Desc、StatusId,其中Foos是EntitySet。最初在第一次提取之后: var item = Foos.FirstOrDefault(f => f.Id = 5); // item values are: Id:5, Desc:"Whatever", StatusId:1 after fetching fro

在使用EF(FirstOrDefault)修改一个值并在另一个集合中使用Where子句请求相同的项之后,我对EF 6.0有一个问题

例如,假设类Foo具有3个属性:Id、Desc、StatusId,其中Foos是EntitySet。最初在第一次提取之后:

var item = Foos.FirstOrDefault(f => f.Id = 5);
// item values are: Id:5, Desc:"Whatever", StatusId:1 after fetching from database

// Change statusId
item.StatusId = 5

// statusItems will not contain above object HOWEVER...
var statusItems = Foos.Where(f => f.StatusId == 5).ToList();

// allItems will contain item, with StatusId = 5
var allItems = Foos.ToList() // Or FirstOrDefault
EF是否会出现这种行为?如果是这样,是否可以强制where子句在DbContext中的附加对象上运行,而不首先指定.ToList()

我发现上述问题的一个可能解决方案是:

var item = Foos.FirstOrDefault(f => f.Id = 5);
// item value are: Id:5, Desc:"Whatever", StatusId: 1 after fetching from database

// Change statusId
item.StatusId = 5

// statusItems will now contain item
var statusItems = Foos.ToList().Where(f => f.StatusId == 5).ToList();
另一种解决方法是将其包装在我假设的事务中,并在修改StatusId属性后调用SaveChanges

我认为,除了知道它是如何工作的(因此,尝试对另一个未更改的属性进行筛选,以确保在筛选之前不会将整个表拖到客户端)之外,没有其他方法可以解决此问题。

发生的情况是,您正在使用的,很可能是
AppendOnly
(默认值),具有特定的行为。实体框架保存已在内存中具体化的对象列表。为了说明正在发生的事情:

var item = Foos.FirstOrDefault(f => f.Id = 5);
实体框架现在在内存中有(Id=5)

var statusItems = Foos.Where(f => f.StatusId == 5).ToList();
从数据库中检索数据库中StatusId=5的所有项目这不包括Id为(5)的对象,因为更改尚未使用
SaveChanges
与数据库同步

var allItems = Foos.ToList();
现在您有了表中所有项目的列表。
AppendOnly
merge选项执行以下操作:

Id=1 - Materialize object
Id=2 - Materialize object
...
Id=5 - Already exists! Give the existing instance
...    
结论是:当使用
AppendOnly
选项时,有两种状态:数据库状态和实体框架缓存状态。如果查询
Foos
列表,它将始终转到数据库,但返回的对象将通过主键值与已经存在的对象相匹配。如果找到现有对象,将返回该实例

这也解释了为什么第二种情况会返回有问题的对象,首先检索整个表,然后过滤它

没有更多的背景,就很难提出解决这个问题的建议。最有可能的情况是,您希望提前保存。

发生的情况是您正在使用的,最有可能的是
AppendOnly
(默认值)具有特定的行为。实体框架保存已在内存中具体化的对象列表。为了说明正在发生的事情:

var item = Foos.FirstOrDefault(f => f.Id = 5);
实体框架现在在内存中有(Id=5)

var statusItems = Foos.Where(f => f.StatusId == 5).ToList();
从数据库中检索数据库中StatusId=5的所有项目这不包括Id为(5)的对象,因为更改尚未使用
SaveChanges
与数据库同步

var allItems = Foos.ToList();
现在您有了表中所有项目的列表。
AppendOnly
merge选项执行以下操作:

Id=1 - Materialize object
Id=2 - Materialize object
...
Id=5 - Already exists! Give the existing instance
...    
结论是:当使用
AppendOnly
选项时,有两种状态:数据库状态和实体框架缓存状态。如果查询
Foos
列表,它将始终转到数据库,但返回的对象将通过主键值与已经存在的对象相匹配。如果找到现有对象,将返回该实例

这也解释了为什么第二种情况会返回有问题的对象,首先检索整个表,然后过滤它

没有更多的背景,就很难提出解决这个问题的建议。很可能,您希望更早地保存。

语句

var statusItems = Foos.Where(f => f.StatusId == 5)
…总是转到数据库。SQL查询只返回此时数据库中状态ID==5的对象。对象
尚未保存,因此未包括在内

因此,您在这里所做的是获取一个具有某些StatusId(可能不是5)的对象,将其更改为StatusId=5,然后获取更多已经具有StatusId=5的对象。上下文中的项数现在是最新查询中的对象数+1

可以强制where子句在DataContext中的附加对象上运行吗

(顺便说一句,DbContext)是的,通过查询本地集合:

Foos.Local.Where(f => f.StatusId == 5)
在这种情况下,此语句将返回到目前为止您在上下文中拥有的所有
Foo

执行
Foos.ToList()
时,将从数据库中获取所有foo。默认情况下,EF不会覆盖其已跟踪的项目。毕竟,你可能会失去你所做的改变。因此,此语句将向尚未存在的
本地
集合追加新的foo项。

该语句

var statusItems = Foos.Where(f => f.StatusId == 5)
…总是转到数据库。SQL查询只返回此时数据库中状态ID==5的对象。对象
尚未保存,因此未包括在内

因此,您在这里所做的是获取一个具有某些StatusId(可能不是5)的对象,将其更改为StatusId=5,然后获取更多已经具有StatusId=5的对象。上下文中的项数现在是最新查询中的对象数+1

可以强制where子句在DataContext中的附加对象上运行吗

(顺便说一句,DbContext)是的,通过查询本地集合:

Foos.Local.Where(f => f.StatusId == 5)
在这种情况下,此语句将返回到目前为止您在上下文中拥有的所有
Foo


执行
Foos.ToList()
时,将从数据库中获取所有foo。默认情况下,EF不会覆盖其已跟踪的项目。毕竟,你可能会失去你所做的改变。因此,此语句将把新的foo项附加到
Local
集合中,而该集合中还没有这些项。

我有一个具有2个PK键(Id和版本)的项,因此我使用它来筛选集合,然后它将找到正确的项。我只是想知道是否有其他方法可以绕过它,而不是保存或使用更大的收藏。尽管如此,你想得越多,它就越有意义