Перезагрузка навигационных свойств в EF6 - PullRequest
0 голосов
/ 23 января 2019

Я прочитал много вопросов от stackoverflow относительно перезагрузки свойства навигации с использованием Context.Entry(entity).Collection(p=>p.Property).Load(), но в моем случае он не дает мне обновленные значения из базы данных.

Для параметров LazyLoading и ProxyCreation установлены значения по умолчанию, которые, как я прочитал, включены по умолчанию.

У меня есть объект Entity 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;
}

Я отладил вышеупомянутое выполнение ReloadNavigationProperties, используя SQL Profiler, и он переходит в базу данных и также генерирует SQL-запрос с объединениями, но мой объект не обновляется даже после перезагрузки.

После неудачной перезагрузки свойств навигации с помощью вышеуказанного метода, я пришел к этому тривиальному подходу, который работает ...

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

Поскольку у меня есть приблизительно 100 TransactionQueryFields для каждого TransactionQuery, и этот вложенный 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 голосов
/ 24 января 2019

Это всего лишь гипотеза, но я думаю, что причина, по которой ваши свойства навигации не перезагружаются, - это отслеживаемые объекты.Я уже испытывал нечто подобное и о методе Load, который doc говорит:

Загружает коллекцию сущностей из базы данных.Обратите внимание, что сущности, которые уже существуют в контексте, не перезаписываются значениями из базы данных.

Когда вы вызываете GetById, вы устанавливаете для параметра trackChanges значение true,С этого момента все загруженные сущностью объекты отслеживаются.Как я уже сказал, я не уверен, что это проблема, но вы можете попробовать установить состояние всех ваших отслеживаемых сущностей на EntityState.Detached.

...