简体   繁体   中英

Reloading navigation properties in EF6

I have read a lot of questions of stackoverflow regarding reloading navigation property using Context.Entry(entity).Collection(p=>p.Property).Load() but in my case it doesn't give me the updated values from database.

LazyLoading and ProxyCreation options are set to their default values, which I have read they are ON by default.

I have an object of entity Test which I have fetched from database using eager loading with all the related properties using below method:

var test = Repository.GetById(testId, null, true, new Expression<Func<Test,object>>[] {
    bt=>bt.Baselining,
    ct=>ct.Baselining.BaselineTestCase,
    dt=>dt.Baselining.BaselineTestCase.Baseline,
    ft=>ft.Baselining.Transaction,
    gt=>gt.Baselining.Transaction>Select(x=>x.Fields)
}); 

public virtual T GetById<T>(int id, Func<T,bool> where = null, bool trackChanges = false, params Expression<Func<T,object>>[] includeProps) 
{
    T item = null;
    IQuerable<T> dbQuery = Context.Set<T>();

    if(includeProps != null)
        foreach(Expression<Func<T,object>> navProp in includeProps)
            dbQuery = dbQuery.Include<T,object>(navProp);

    if(where == null)
    {    
        if(!trackChanges) item = dbQuery.AsNoTracking().FirstOrDefault(t=>t.Id == id);
        else item = dbQuery.FirstOrDefault(t=>t.Id == id);
    }
    else
    {
        if(!trackChanges) item = dbQuery.AsNoTracking().Where(where).FirstOrDefault(t=>t.Id == id);
        else item = dbQuery.Where(where).FirstOrDefault(t=>t.Id == id);
    }
    return item;
}

I am trying to reload Baselining.Transaction.Fields using

Repository.Reload(test);
Repository.Reload(test.Baselining.BaselineTestCase);
Repository.Reload(test.Baselining.BaselineTestCase.Baseline);
Repository.ReloadNavigationProperties(test.Baselining, x=>x.Transaction);
foreach(var tq in test.Baselining.Transaction)
    Repository.ReloadNavigationProperties(tq, x=>x.Fields);

Repository methods goes something like:

public virtual void ReloadNavigationProperties(TEntity,TElement>(TEntity entity, Expression<Func<TEntity,ICollection<TElement>>> navProp) where TEntity : class where TElement : class
{
    Context.Entry(entity).Collection(navProp).Load();
}

public virtual T Reload<T>(T entity) where T : class {
    Context.Entry(entity).Reload();
    return entity;
}

I have debugged the above ReloadNavigationProperties execution using SQL Profiler and it does go to database and generates a SQL query with joins as well, but my object is not updated even after the reload.

After failing to reload navigation properties with above method, I came to this trivial approach, which works...

foreach(var tq in test.Baselining.Transaction)
    foreach(var tqfs in tq.Fields) 
        Repository.Reload(tqfs);

Because I have approx 100 TransactionQueryFields for each TransactionQuery and this nested foreach goes 100 times to reload each field and its very very slow and it should be slow...

Here are the entities

public class Test 
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int id {get;set;}
    public virtual Baselining Baselining {get;set;}
    public virtual ICollection<TestExecutionResult> TestCaseResults {get;set;} = new List<TestExecutionResult>();
}

public class Baselining 
{
    public Baselining() {}
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int id {get;set;}
    public DateTime BaseliningDate {get;set;}
    public virtual BaselineTestCase BaselineTestCase {get;set;}
    public virtual ICollection<TransactionQuery> Transaction {get;set;} = new List<TransactionQuery>();
}

public class BaselineTestCase 
{
    public BaselineTestCase() {}
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int id {get;set;}
    public virtual Baseline Baseline {get;set;}
    public virtual ICollection<Baselining> Baselinings {get;set;} = new List<Baselining>();
    public Baselining LastBaselining {
        get {return Baselinings.OrderBy(x=>x.BaseliningDate).LastOrDefault(); }
    }
}

public class TransactionQuery : TransactionItem 
{
    public TransactionQuery() {}
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public override int id {get;set;}
    public virtual Baselining Baselining {get;set;}
    public virtual ICollection<TransactionQueryField> Transaction {get;set;} = new List<TransactionQueryField>();
}

public class TransactionQueryField : TransactionItem 
{
    public TransactionQueryField() {}
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public override int id {get;set;}
    public bool Compare {get;set;}
    public bool Critical {get;set;}
}

public abstract class TransactionItem : BaseEntity<int> {
    public string TestResultCode {get;set;}
}

public abstract class BaseEntity<T> {
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public virtual T Id {get;set;}
}

I want to understand why eager loading with navigation properties is not loading the updated data. Because according to my understanding, if I eager load anything it should make a round-trip to database and fetch updated data. But even eager loading with reload, it doesn't gives me updated values.

I am sorry if I didn't explain it properly, although I will appreciate any help regarding how to load my fields faster may be with one single db round-trip.

This is just an hypothesis but I think the reason for which your navigation properties are not reloaded is tracked entities. I have already experienced something like this and about the Load method the doc says:

Loads the collection of entities from the database. Note that entities that already exist in the context are not overwritten with values from the database.

When you call the GetById , you set the parameter trackChanges on true. From now on, all the eager-loaded entities are tracked. As I said, I am not sure if this is the problem but you could try setting the state of all your tracked entities to EntityState.Detached .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM