【问题标题】:Where clause followed by FirstOrDefault returning the same valueWhere 子句后跟 FirstOrDefault 返回相同的值
【发布时间】:2015-03-30 13:34:43
【问题描述】:

我有一个类有这样的功能:

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);
    // ...
}

问题是CurrentTarget 绝对是不同的对象,它们对于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);

它在第一次调用时通过,在第二次调用时失败。这似乎是不可能的。

【问题讨论】:

  • 据我所见,您正在访问同一上下文ctx 的同一对象Foos,独立于CurrentTarget。为什么会和自己不同?
  • @Thaoden,请注意他正在通过this.Code 进行过滤,它将为不同的类实例保存不同的值
  • @GiorgiNakeuri 我的错
  • @Matt Burland,在调试模式下,当您在var obj = ctx.Foos.Where(f => f.Code == this.Code).FirstOrDefault(); 上有断点时,那里的一切都正确吗?你看到不同的代码吗?您还看到退货线上有不同的退货对象吗?你可能会更好地发布你是如何创建你的课程的吗?还有and fails on the second可以添加异常抛出吗?
  • 是哪个 EF 版本?您是否尝试过从 linq 查询中删除 this.Code 并使用值为 this.code 的局部变量?

标签: c# entity-framework sql-server-2012


【解决方案1】:

实体框架上下文是一个identity map,即它在数据库中保留每个实体的单个副本。即使从数据库中重新获取对象,EF 也不会修改本地副本中的值。我认为这是因为它会干扰更改跟踪,并且可能会覆盖同时进行的客户端更改。

所以设计上curr == targetCode 始终是从数据库中获取的第一个值,除非它在客户端代码中被修改(在这种情况下currtarget 显然都会修改值)。

【讨论】:

  • 如果我们考虑简单的控制台应用程序,它只是创建上下文,然后从不同 ID 的上下文中选择 2 个订单,你想说这两个对象是相同的吗?
  • 我不怀疑这与身份映射有关,但它仍然没有一点意义,因为我不能在同一上下文上进行两次调用,将不同的值传递给where 子句并获得两个 不同的 对象。在第二种情况下,返回的对象在检索时甚至不满足Where 子句。
  • @MattBurland 你是对的。那没有意义。通过您的发现curr == target 我得出结论,不同的参数确实产生了相同的结果(毕竟这是可能的)。如果 EF 没有适当的视图主键(即由保证唯一的字段组合组成的键),这也是可能发生的问题。
  • 看起来问题在于 EF 认为密钥实际应该是什么而不是它应该是什么。我支持您,因为您对身份映射的评论确实为我指明了思考它用作密钥的方向。我仍然不确定这对我来说是否真的有意义,因为显然不满足 Where 子句,但将 Code 标记为 EntityKey 似乎确实解决了这个特殊问题。
  • 啊,很高兴你找到它!
【解决方案2】:

好的 - 我想我找到了问题所在。 @GertArnold 的回答帮助我找到了原因。问题是,无论出于何种原因,当我将视图导入实体框架时,EF 决定应该使用数据库中的另外两个(且不相关的)字段来构造键,而不是 Code(实际上是键) .我在edmx 文件中将Entity Key 设置为True,现在它按预期工作。

我猜是因为,就 EF 而言,我没有更改主键,即使它实际上不符合 Where 标准,也可以返回相同的对象。它生成的整个 SQL 具有可怕的误导性和混乱性,因为我猜它从未真正执行过。

【讨论】:

  • @GertArnold:我会尽可能(除非我忘记,我可能会忘记)。
猜你喜欢
  • 2021-05-30
  • 2013-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
  • 1970-01-01
  • 1970-01-01
  • 2019-06-29
相关资源
最近更新 更多