实体框架:重新查找最近添加到上下文的对象

dov*_*luk 38 entity-framework

我正在使用实体框架,我遇到了"重新找到"我刚刚创建的对象的问题...基本上它是这样的:

string theId = "someId";

private void Test()
{
  using(MyEntities entities = new MyEntities())
  {
    EntityObject o = new EntityObject();
    o.Id = theId;
    entities.AddToEntityObject(o);
    CallSomeOtherMethod(entities);
  }
}

void CallSomeOtherMethod(MyEntities ents)
{
  EntityObject search = ents.EntityObject.FirstOrDefault(o => o.Id == theId);
  if(search == null) 
  {
    Console.WriteLine("wha happened???");
  }
}
Run Code Online (Sandbox Code Playgroud)

(不保证代码可以正常运行 - 这一切都来自我的脑海)

为什么查询"找不到"刚刚创建的EntityObject?

如果我在AddToEntityObject之后调用SaveChanges()它可以工作(这并不让我感到惊讶),但为什么它不能正确地从缓存中拉出来?

我对这些东西仍然很绿,所以我希望有一些非常简单的东西,我只是忽略了......

谢谢

Rad*_*ady 27

新添加的对象在本地数据源中,因为它没有在数据库中保留,所以你可能会说 __CODE__


Dan*_*ner 19

发生这种情况是因为ents.EntityObject.WhatEver始终查询数据源.这是一个设计决定.他们这样做,因为否则他们必须针对数据源执行查询,针对本地缓存,然后合并结果.正如其中一位开发人员在博客中指出的那样(不记得究竟在哪里)他们无法始终如一地处理这个问题.

你可以想象,你需要妥善处理边缘情况.您可以找到您在本地创建的ID,由数据库中的其他人创建.这将迫使您准备好处理(几乎)每个查询的冲突.也许他们可以创建查询本地缓存的方法和查询数据源的方法,但这也不是聪明的.

您可以查看透明延迟加载实体框架.这将取代普通的代码生成器,您将获得在访问时自动填充其相关实体集合和实体引用的实体.这避免了所有

if (!Entity.ReleatedEntities.IsLoaded)
{
   Entity.RelatedEntities.Load();
}
Run Code Online (Sandbox Code Playgroud)

代码片段.您可以查询集合,因为它们始终是隐式加载的.但这个解决方案也不完美.有一些问题.例如,如果您创建新实体并访问相关实体的集合,则会出现异常,因为代码无法从数据库中检索相关实体.还有一个与数据绑定有关的问题,可能还有一些我不知道的问题.

好的是你得到了源代码,并且能够自己修复问题,如果我找到一些时间,我将检查第一个问题.但我很确定它不会那么容易修复,因为我预计如果刚刚创建的实体不是预期的行为,有些情况就是没有命中数据库.


Jan*_*son 18

我处于同样的境地.我写了这个扩展方法,至少对我来说解决了问题(我没有问题,即我的上下文中的冲突......)

    public static IEnumerable<T> WhereInclAdded<T>(this ObjectSet<T> set, Expression<Func<T, bool>> predicate)  where T : class
    {
        var dbResult = set.Where(predicate);

        var offlineResult = set.Context.ObjectStateManager.GetObjectStateEntries(EntityState.Added).Select(entry => entry.Entity).OfType<T>().Where(predicate.Compile());

        return offlineResult.Union(dbResult);
    }
Run Code Online (Sandbox Code Playgroud)

  • 对于dbset,我将其更改为:var offlineResult = set.Local.Where(predicate.Compile()); (5认同)
  • 注意这里有一个细微的细节:.使用IQueryable,而本地Where使用IEnumerable.如果在第一个中使用.Where(expression.Compile()),它将调用IEnumerable,导致整个表被加载到内存中.如果您使用此代码作为您自己的基础,那么只是一个细节. (2认同)