Is DbSet<>.Local something to use with special care?

后端 未结 3 1086
忘掉有多难
忘掉有多难 2021-02-05 14:35

For a few days now, I have been struggling with retrieving my entities from a repository (DbContext).

I am trying to save all the entities in an atomic act

相关标签:
3条回答
  • 2021-02-05 14:55

    If you want to be able to 'easily' issue a query against the DbSet and have it find newly created items, then you will need to call SaveChanges() after each entity is created. If you are using a 'unit of work' style approach to working with persistent entities, this is actually not problematic because you can have the unit of work wrap all actions within the UoW as a DB transaction (i.e. create a new TransactionScope when the UoW is created, and call Commit() on it when the UoW completed). With this structure, the changes are sent to the DB, and will be visible to DbSet, but not visible to other UoWs (modulo whatever isolation level you use).

    If you don't want the overhead of this, then you need to modify your code to make use of Local at appropriate times (which may involve looking at Local, and then issuing a query against the DbSet if you didn't find what you were looking for). The Find() method on DbSet can also be quite helpful in these situations. It will find an entity by primary key in either Local or the DB. So if you only need to locate items by primary key, this is pretty convenient (and has performance advantages as well).

    0 讨论(0)
  • 2021-02-05 15:06

    For those who come after, I ran into some similar issues and decided to give the .Concat method a try. I have not done extensive performance testing so someone with more knowledge than I should feel free to chime in.

    Essentially, in order to properly break up functionality into smaller chunks, I ended up with a situation in which I had a method that didn't know about consecutive or previous calls to that same method in the current UoW. So I did this:

    var context = new MyDbContextClass();
    var emp = context.Employees.Concat(context.Employees.Local).FirstOrDefault(e => e.Name.Contains("some name"));
    
    0 讨论(0)
  • 2021-02-05 15:12

    As mentioned by Terry Coatta, the best approach if you don't want to save the records first would be checking both sources.

    For example:

    public Person LookupPerson(string emailAddress, DateTime effectiveDate)
    {
        Expression<Func<Person, bool>> criteria = 
            p =>
                p.EmailAddress == emailAddress &&
                p.EffectiveDate == effectiveDate;
    
        return LookupPerson(_context.ObjectSet<Person>.Local.AsQueryable(), criteria) ?? // Search local
               LookupPerson(_context.ObjectSet<Person>.AsQueryable(), criteria); // Search database
    }
    
    private Person LookupPerson(IQueryable<Person> source, Expression<Func<Person, bool>> predicate)
    {
        return source.FirstOrDefault(predicate);
    }
    
    0 讨论(0)
提交回复
热议问题