【问题标题】:Why would IQueryable<T>.FirstorDefault() return the same reference everytime of one object type and not another?为什么 IQueryable<T>.FirstorDefault() 每次返回一个对象类型而不是另一个对象类型时都返回相同的引用?
【发布时间】:2011-04-25 15:37:31
【问题描述】:

我在使用 LINQ to SQL 时遇到了这个问题,但似乎无法从有任何意义的角度看待它。我有一个 IQueryable 为:

var personnel = from p in dc.Resources select p;
var p1 = personnel.FirstOrDefault();
var p2 = personnel.FirstOrDefault();
objec.ReferenceEquals(p1,p2);

上面的 ReferenceEquals() 调用每次都评估为 false(我认为应该如此,因为每次调用 FirstOrDefault() 都会生成一个新的 T-SQL 调用)。但是,我还有另一个 IQueryable(同一数据库中的不同表):

var accounts = from a in dc.Accounts select a;
var a1 = accounts.FirstOrDefault();
var a2 = accounts.FirstOrDefault();
object.ReferenceEquals(a1,a2);

这一次 ReferenceEquals() 调用每次都评估为真......有什么想法怎么可能? (注意:我已经检查以确认 a1、a2、p1 和 p2 都评估为各自的类而不是 null)。

【问题讨论】:

  • p1 和 p2 是同一人事记录吗? a1和a2是同一个账户记录吗?我的意思是如果返回的记录在对FirstOrDefault 的两次调用中具有相同的主键?
  • 两个答案中提到的缓存实际上是身份映射模式,它是所有类似 ORM 的工具的关键特性。

标签: linq-to-sql iqueryable


【解决方案1】:

虽然每次调用FirstOrDefault时LINQ to SQL都会执行查询,但是对于从数据库返回的每个对象,LINQ to SQL都会检查它是否在缓存中,如果是,它会丢弃获取的数据并简单地返回缓存的对象。

【讨论】:

  • 原来 Resource 表是唯一没有主键的表,因此被标记为只读(在 DC 中),因此没有启用更改跟踪,这意味着没有任何缓存...为了解决这个问题,我将我的 [Column] 属性之一(在 Personnel 类上)标记为主键。感谢您为我指明正确的方向!
【解决方案2】:

第一个实体一定有什么东西阻止了 DC 给你缓存的版本。我希望第二个示例是您经常看到的行为; DC 将识别您何时请求已加载的对象,并在可能的情况下将相同的引用交给您。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-20
    • 2013-12-04
    • 1970-01-01
    • 1970-01-01
    • 2017-10-06
    • 1970-01-01
    相关资源
    最近更新 更多