【问题标题】:Querying objects after AddObject before SaveChanges?在 SaveChanges 之前在 AddObject 之后查询对象?
【发布时间】:2011-08-09 01:54:51
【问题描述】:

在 EntityFramework 中,是否可以在调用 SaveChanges 方法之前使用 AddObject 查询刚刚添加到上下文中的对象?

谢谢

【问题讨论】:

    标签: entity-framework entity-framework-4


    【解决方案1】:

    要持久化一个实体,您通常将其添加到上下文中的DbSet

    例如

    var bar = new Bar();
    bar.Name = "foo";
    var context = new Context();
    context.Bars.Add(bar);
    

    奇怪,查询context.Bars,找不到刚刚添加的实体

    var howMany = context.Bars.Count(b => b.Name == "foo");
    // howMany == 0
    

    context.SaveChanges() 之后的同一行将产生1

    DbSet 似乎不知道更改直到它们被持久化到 db 上。

    幸运的是,每个DbSet 都有一个Local 属性,其作用类似于DbSet 本身,但它反映了所有内存中的操作

    var howMany = context.Bars.Local.Count(b => b.Name == "foo");
    // howMany == 1
    

    您也可以使用Local添加实体

    context.Bars.Local.Add(bar);
    

    并摆脱实体框架的怪异行为。

    【讨论】:

    • 这是否会返回已添加但未保存的项目以及数据库中的项目?
    • context.Bars.Local 最初为空,直到从数据库加载 context.Bars。然后它可以同时拥有内存中的项目和数据库中的项目。不建议在大型数据集上使用 Local。更多本地信息:msdn.microsoft.com/en-us/data/jj592872
    • 这是特定于 EF 4 之后的版本吗?我的ObjectSet 上没有Local 属性,但我也有ObjectSetObjectContext 对象,而不是DbSetDbContext
    • @Aximili 你能解释一下吗:“直到 context.Bars 从数据库中加载”。我怎样才能触发它?我想同时查询内存和数据库
    【解决方案2】:

    你可以像这样查询对象,

    context.ObjectStateManager.GetObjectStateEntries(EntityState.Added).Select(obj => obj.Entity).OfType<TheEntityType>()
    

    这将查询处于添加状态的对象。如果你也想要其他状态,你可以像这样将所有其他状态传递给GetObjectStateEntries 方法。

    GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Unchanged)
    

    【讨论】:

      【解决方案3】:

      在休眠状态下,瞬态实例已经附加到上下文中。刚刚偶然发现了这个 EF 限制。

      我没有设法将 ObjectSet 与其瞬态实体 ObjectSet.Local 相交/联合,但对于我们的用例,以下 find 方法就足够了。

      在我们的例子中,我们在迭代期间根据唯一标准创建一些惰性实体

      查找方法

      如果您使用的是存储库模式,您可以创建如下方法:

      public interface IRepository<T> where T : class, IEntity
      {
          /// <summary>
          /// Finds the unique Entity with the given predicate.
          /// Depending on implementation also checks transient / local (unsaved) Entities.
          /// </summary>
          /// <param name="predicate"></param>
          /// <returns></returns>
          IQueryable<T> FindAll(Expression<Func<T, bool>> predicate);
      }
      
      public class EfRepository<T> : IRepository<T> where T : class, IEntity
      {
          protected readonly ObjectContext context;
          protected readonly ObjectSet<T> objectSet;
      
          /// <summary>
          /// Creates a new repository of the given context.
          /// </summary>
          /// <param name="context"></param>
          public EfRepository(ObjectContext context)
          {
              if (context == null)
                  throw new ArgumentException("Context must not be null.");
              this.context = context;
              this.objectSet = context.CreateObjectSet<T>();
          }
      
          /// <summary>
          /// Also takes local context into consideration for unsaved changes
          /// </summary>
          /// <param name="predicate"></param>
          /// <returns></returns>
          public T Find(Expression<Func<T, bool>> predicate)
          {
              T result = this.objectSet.Where(predicate).FirstOrDefault();
              if (result == null)
                  result = this.objectSet.Local().Where(predicate).FirstOrDefault();
              return result;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多