1

我有两个应用程序:一个应用程序是 asp.net,另一个是在后台运行的 Windows 服务。

在后台运行的 Windows 服务正在对数据库执行一些任务(读取和更新),而用户可以通过 asp.net 应用程序对数据库执行其他操作。所以我很担心,例如,在 Windows 服务中,我收集了一些满足条件的记录,然后对它们进行迭代,例如:

IQueryable<EntityA> collection = context.EntitiesA.where(<condition>)
foreach (EntityA entity in collection)
{
  // do some stuff
}

那么,如果用户修改了稍后在循环迭代中使用的记录,那么 EF 会考虑该记录的什么值?执行时检索到的原件:

context.EntitiesA.where(<condition>)

还是由用户修改并位于数据库中的新的?

据我所知,在迭代期间,EF 会根据需要获取每条记录,我的意思是,一条一条地读取,因此在为下一次迭代读取下一条记录时,该记录对应于从以下位置收集的记录:

context.EntitiesA.where(<condition>)

还是位于数据库中的那个(用户刚刚修改的那个)?

谢谢!

4

3 回答 3

2

就这在 EF 中的工作方式而言,这里有几个过程将发挥作用。

  1. 查询仅在枚举上执行(这有时称为查询具体化)此时将执行整个查询
  2. 延迟加载仅影响上述示例中的导航属性。where语句的结果集会被一次性拉下来。

那么在你的情况下这意味着什么:

//nothing happens here you are just describing what will happen later to make the 
// query execute here do a .ToArray or similar, to prevent people adding to the sql 
// resulting from this use .AsEnumerable
IQueryable<EntityA> collection = context.EntitiesA.where(<condition>); 
//when it first hits this foreach a 
//SELECT {cols} FROM [YourTable] WHERE [YourCondition] will be performed
foreach (EntityA entity in collection)
{
    //data here will be from the point in time the foreach started (eg if you have updated during the enumeration in the database you will have out of date data)
    // do some stuff
}
于 2013-06-20T20:35:18.433 回答
0

如果您真的担心会发生这种情况,那么请预先获取一个 id 列表,并DbContext为每个 id 单独处理它们(或者说在每批 10 个之后)。就像是:

IList<int> collection = context.EntitiesA.Where(...).Select(k => k.id).ToList();
foreach (int entityId in collection)
{
    using (Context context = new Context())
    {
        TEntity entity = context.EntitiesA.Find(entityId);
        // do some stuff
        context.Submit();
    }
}
于 2013-06-20T20:36:04.223 回答
0

我认为您的问题的答案是“视情况而定”。您描述的问题称为“不可重复读取”,可以通过设置适当的事务隔离级别来防止发生。但它会带来性能成本和潜在的死锁。

有关更多详细信息,您可以阅读

于 2013-06-20T20:46:53.373 回答