In a different post I asked for clarification when to use DbSet<TEntity>.Local
. I did not get an answer yet, I think the question may contain too much information. After digging a little deeper I can ask a more specific question.
Hopefully you guys can explain which of the two options to choose in my scenario.
What do I want to achieve?
I am trying to retrieve entities from my
Repository
. The entities are still in the 'added' state (i.e. I did not yet call theSaveChanges
method). I need this, because I want to store the entities in one atomic action, so I must postpone theSaveChanges
call until after I validated the complete model.Further more I need to conform to the IQueryable interface, because I have dependent code that uses the extension method
Include
onQueryable
to lazy load navigation properties.
What did I try?
A load of things over the last few days, but it boiled down to the following two different approaches:
- Retrieve entities that are in 'added' state via the
DbSet<TEntity>.Local
property - Retrieve entities that are in 'added' state via the
DbContext.ChangeTracker
A code example to visualize the different approaches
public void AddAndRetrieveUncommittedEntityFromDbContext()
{
Database.SetInitializer(new DropCreateDatabaseAlways<TestContext>());
var testContext = new TestContext();
// Initialize the entities and store them in the repository
var tenant = new Tenant { Name = "test", Guid = Guid.NewGuid().ToString() };
var user = new User { Name = "bas", EmailAddress = "bas@domain.com", Password = "password" };
tenant.Users.Add(user);
testContext.Tenants.Add(tenant);
// NOTE: I did not call `SaveChanges` yet, but still I want to retrieve
// the tenant from my repository
///////////////////////////////////////////////
// Alternative one, use the ChangeTracker... //
///////////////////////////////////////////////
IEnumerable<DbEntityEntry<Tenant>> tenants = testContext.ChangeTracker.Entries<Tenant>();
IQueryable<Tenant> query = tenants.Select(dbEntityEntry => dbEntityEntry.Entity).AsQueryable();
Tenant storedTenant = query.
Where(ent => ent.Name.Equals("test")).
Include(ent => ent.Users).First();
Assert.IsNotNull(storedTenant.Users.FirstOrDefault());
// hurray, it passes
///////////////////////////////////////////////
// Alternative two, use the 'Local' property //
///////////////////////////////////////////////
IQueryable<Tenant> query2 = testContext.Tenants.Local.AsQueryable();
Tenant storedTenant2 = query2.
Where(ent => ent.Name.Equals("test")).
Include(ent => ent.Users).First();
Assert.IsNotNull(storedTenant2.Users.FirstOrDefault());
// hurray, it passes
////////////////////////////////////////////////
// For completeness => entity is not in DbSet //
////////////////////////////////////////////////
IQueryable<Tenant> query3 = testContext.Tenants.AsQueryable();
Tenant storedTenant3 = query3.
Where(ent => ent.Name.Equals("test")).
Include(ent => ent.Users).FirstOrDefault();
Assert.IsNotNull(storedTenant3);
// Fails, because the entity is not yet available in the DbSet 'testContext.Tenants'
}
The testContext is pretty straight forward:
public class TestContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Tenant> Tenants { get; set; }
public TestContext() : base("Test1") {}
}
The questions
- What is the advised way to retrieve all entities (i.e. including entities in 'added' state)?
- What are the pros and cons for
DbSet<TEntity>.Local
andChangeTracker
?
Many many thanks in advance!