DbContext not returning local objects

c# entity-framework-core

Question

I'm using the Unit of Work pattern that calls dbcontext.SaveChanges after everything has executed on a webapi request. In part of the request, I add a new customer to the dbcontext.

dbContext.Customers.Add(new Customer());

Later in the request( usually inside of a domain event handler), I'm using the same dbcontext to pull the customer back out.

_dbContext.Customers.FirstOrDefault(x => x.Id == id);


public abstract class Customer
{
    public Customer()
    {
        Id = Guid.NewGuid();
    }

}

I've verified that dbContext.Customers.Local has the object that I'm expecting, but it doesn't seem to be fetching the local object out. Could this be caused by the fact that Customer is an abstract class, implemented by DirectCustomer and InDirectCustomer?

Why? Can I change this behavior through configuration? Maybe I have to merge the local and database results( kinda hacky ).

Update:

class Program
{
    static void Main(string[] args)
    {
        MyDbContext context = new MyDbContext();

        Guid customerGuid = Guid.NewGuid();

        context.Customers.Add(new DirectCustomer()
        {
            Id = customerGuid
        });

        // This does not work, customerFromLocal1 is null
        var customerFromLocal1 = context.Customers.FirstOrDefault(x => x.Id == customerGuid);

        // This does work, customerFromLocal2 is NOT null
        var customerFromLocal2 = context.Customers.Find(customerGuid);


    }
}


public class MyDbContext : Microsoft.EntityFrameworkCore.DbContext
{
    public DbSet<Customer> Customers { get; set; }


    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("server=.\\sqlexpress;integrated security=true;database=EFCoreDeepDive2");
        base.OnConfiguring(optionsBuilder);
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<DirectCustomer>();
        builder.Entity<IndirectCustomer>();
    }

}

public abstract class Customer
{
    public Guid Id { get; set; }
}

public class DirectCustomer : Customer
{

}

public class IndirectCustomer : Customer
{
    public Guid ParentCustomerId { get; set; }
}
1
2
9/14/2017 2:05:52 PM

Accepted Answer

In EF Core, Linq operators (like FirstOrDefault(), ToList() etc. & their counter-parts in async) causes the query to be evaluated against the server. For query, the server data is source of truth. It would combine return objects if they are loaded in memory already but it would check with server first.

When you add a new entity object to context, the object exists in changetracker but it won't be saved to server till you call SaveChanges(). So, after adding entity & before calling SaveChanges for any query which will be evaluated against server will have no information about the newly added entity and will not return any results related to it.

If you are trying to find an entity object by its key values in current context instance, which may or may not have been saved, then use context.DbSet.Find() method (there are other variations defined on context also. Find method first checks the ChangeTracker to find the object, which contains all objected loaded in memory & added/modified objects. If it does not find then it will load the object from server. In your case since you want to find entity which was added to context but not saved, Find will give you expected result.

Note: DbSet.Local contains all the entities of the type of DbSet being tracked by current context. Therefore the added entity is available there but not on DbSet directly. DbSet is IQueryable in order to allow writing server queries against it.

4
9/20/2017 7:44:51 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow