Querying objects after AddObject before SaveChange

2019-01-09 01:07发布

In EntityFramework, is that possible to query the objects that have just been added to the context using AddObject but before calling the SaveChanges method?

Thanks

3条回答
放荡不羁爱自由
2楼-- · 2019-01-09 01:48

To persist an entity you usually add it to it's DbSet in the context.

For example

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

Surprisingly, querying context.Bars, the just added entity cannot be found

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

After context.SaveChanges() the same line will result 1

The DbSet seems unaware to changes until they're persisted on db.

Fortunately, each DbSet has a Local property that acts like the DbSet itself, but it reflect all in-memory operations

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

You can also use Local to add entities

context.Bars.Local.Add(bar);

and get rid of the weird behavior of Entity Framework.

查看更多
爷、活的狠高调
3楼-- · 2019-01-09 02:02

In hibernate transient instances are already attached to context. Just stumbled upon this EF restriction.

I did not managed to intersect/union the ObjectSet with its transient entities ObjectSet.Local but for our usecase the below find method is sufficient.

In our cases we create some entities lazy depending on unique criteria during an iteration

Find method

If you are using an repository pattern you can create a method like:

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;
    }
}
查看更多
Melony?
4楼-- · 2019-01-09 02:06

you can query objects like this,

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

this will query the objects which are in added state. If you want other states too you can pass all other states to GetObjectStateEntries method like this.

GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Unchanged)
查看更多
登录 后发表回答