Querying objects after AddObject before SaveChanges?
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.
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)
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;
}
}