我有一个具有类似功能的类:
public string Code { get; set; }
public Dal.Foo GetFoo(Dal.MyContext ctx)
{
var obj = ctx.Foos.Where(f => f.Code == this.Code).FirstOrDefault();
return obj;
}
现在这通常很好用。但是,我在另一个类中调用它的另一个函数是这样的:
using (var ctx = new Dal.MyContext())
{
var curr = parameters.Current.GetFoo(ctx);
var target = parameters.Target.GetFoo(ctx);
// ...
}
问题是Current
和Target
肯定是不同的对象,它们对Code
肯定有不同的值,但是当我执行此代码时,我结束了使用curr
和target
的相同对象!?! curr == target
会返回真正不应该的true
。我甚至查看了从GetFoo
方法生成的SQL,它正确地使用不同的参数调用数据库,并且在SQL Server Management Studio中执行这些命令会返回两个不同的结果。我可以通过不向他们提供相同的上下文来解决问题(即将第二个调用放入其自己的using
块中并使用新的MyContext
),但这实际上不应该是必要的。
这里发生了什么?
编辑:不确定这是否相关,但我应该提到我实际上是在SQL服务器上查看视图而不是表。尽管如此,它仍然生成看起来正确的SQL并传递Where
子句的正确参数。
另一个编辑:
我尝试在获得obj
的行之后添加此内容:
System.Diagnostics.Debug.Assert(obj.Code == this.Code);
它传递第一个呼叫并在第二个呼叫失败。这似乎不可能。
答案 0 :(得分:1)
实体框架上下文是identity map,即它保留数据库中每个实体的单个副本。即使从数据库中重新获取对象,EF也不会修改本地副本中的值。我认为这是因为它会干扰变更跟踪,并且可能会覆盖同时发生的客户端变更。
因此,设计curr == target
和Code
始终是从数据库中获取的第一个值,除非它在客户端代码中被修改(在这种情况下curr
和{{1两者显然都有修改后的值。)
答案 1 :(得分:1)
好的 - 我想我已经找到了问题所在。 @ GertArnold的回答帮助我找到了原因。问题是,无论出于何种原因,当我将视图导入Entity Framework时,EF决定使用数据库中的另外两个(和不相关的)字段来构造密钥,而不是Code
(实际上是键)。我在Entity Key
文件中将True
设置为edmx
,现在它按预期工作了。
我想因为,就EF而言,我没有改变主键,即使它没有真正符合Where
条件,也可以返回相同的对象。它生成的整个SQL是非常误导和混乱的,因为我猜它从来没有真正执行过。