重新加载EF6中的导航属性

时间:2019-01-23 08:09:44

标签: c# linq entity-framework-6 dbcontext

关于使用Context.Entry(entity).Collection(p=>p.Property).Load()重新加载导航属性,我已经阅读了很多关于stackoverflow的问题,但就我而言,它没有给我来自数据库的更新值。

LazyLoading和ProxyCreation选项设置为它们的默认值,据我了解,它们默认情况下处于启用状态。

我有一个实体Test对象,我已使用以下方法从数据库中使用所有相关属性进行紧急加载:

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;
}

我正在尝试使用

重新加载Baselining.Transaction.Fields
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);

存储库方法类似于:

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;
}

我已经使用SQL事件探查器调试了上面的ReloadNavigationProperties执行,它确实进入了数据库并生成了带有联接的SQL查询,但是即使重新加载后我的对象也没有更新。

在无法使用上述方法重新加载导航属性后,我想到了这种简单的方法,该方法行之有效...

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

因为每个TransactionQuery都有大约100个TransactionQueryFields,并且这个嵌套的foreach会重载100次以重新加载每个字段,所以它非常慢,应该很慢...

这是实体

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;}
}

我想了解为什么急于加载导航属性而不加载更新的数据。因为根据我的理解,如果我急于加载任何东西,它应该往返数据库并获取更新的数据。但是,即使渴望通过重新加载进行加载,也无法获得更新的值。

很抱歉,如果我没有正确解释,尽管希望通过单个数据库往返来获得有关如何更快地加载字段的任何帮助。

1 个答案:

答案 0 :(得分:0)

这只是一个假设,但我认为未重新加载导航属性的原因是跟踪的实体。 我已经经历过类似的事情,并且关于doc所说的Load方法:

  

从数据库加载实体集合。请注意,实体   上下文中已经存在的值不会被的值覆盖   数据库。

调用GetById时,将参数trackChanges设置为true。从现在开始,将跟踪所有渴望加载的实体。 如我所说,我不确定是否是问题所在,但您可以尝试将所有跟踪实体的状态设置为EntityState.Detached