У меня есть простое соотношениеEntityFramework не обновляет навигационные свойства
Я создал простое приложение с моделью, как показано выше. Модель в приложении должна обновляться каждый раз, когда изменяется БД. Я могу получить последние изменения, вызвав хранимую процедуру GetDBChanges. (См метод T1Elapsed)
здесь приложение:
class Program
{
private static int? _lastDbChangeId;
private static readonly MASR2Entities Model = new MASR2Entities();
private static readonly Timer T1 = new Timer(1000);
private static readonly Timer T2 = new Timer(1000);
private static Strategy _strategy = null;
static void Main(string[] args)
{
using (var ctx = new MASR2Entities())
{
_lastDbChangeId = ctx.GetLastDbChangeId().SingleOrDefault();
}
_strategy = Model.Strategies.FirstOrDefault(st => st.StrategyId == 224);
T1.Elapsed += T1Elapsed;
T1.Start();
T2.Elapsed += T2Elapsed;
T2.Start();
Console.ReadLine();
}
static void T2Elapsed(object sender, ElapsedEventArgs e)
{
Console.WriteLine("All rules: " + Model.StrategyRules.Count());
Console.WriteLine("Strategy: name=" + _strategy.Name + " RulesCount=" + _strategy.StrategyRules.Count);
}
private static void T1Elapsed(object sender, ElapsedEventArgs e)
{
T1.Stop();
try
{
using (var ctx = new MASR2Entities())
{
var changes = ctx.GetDBChanges(_lastDbChangeId).ToList();
foreach (var dbChange in changes)
{
Console.WriteLine("DbChangeId:{0} {1} {2} {3}", dbChange.DbChangeId, dbChange.Action, dbChange.TableName, dbChange.TablePK);
switch (dbChange.TableName)
{
case "Strategies":
{
var id = Convert.ToInt32(dbChange.TablePK.Replace("StrategyId=", ""));
Model.Refresh(RefreshMode.StoreWins, Model.Strategies.AsEnumerable());
}
break;
case "StrategyRules":
{
var id = Convert.ToInt32(dbChange.TablePK.Replace("StrategyRuleId=", ""));
Model.Refresh(RefreshMode.StoreWins, Model.StrategyRules.AsEnumerable());
}
break;
}
_lastDbChangeId = dbChange.DbChangeId;
}
}
}
catch (Exception ex)
{
Console.WriteLine("ERROR: " + ex.Message);
}
finally
{
T1.Start();
}
}
}
Когда я запускаю его, это пример вывода:
All rules: 222
Strategy: name=Blabla2 RulesCount=6
затем добавить строку в дочерней таблице (Стратегия Правило),
DbChangeId:1713 I StrategyRules StrategyRuleId=811
All rules: 223
Strategy: name=Blabla2 RulesCount=7
и, наконец, я удалить строку из StrategyRules
DbChangeId:1714 D StrategyRules StrategyRuleId=811
All rules: 222
Strategy: name=Blabla2 RulesCount=7
Почему RulesCount все еще 7? Как я могу заставить EF обновить «навигационное свойство»?
Что мне здесь не хватает?
--- EDIT --- для покрытия ответ Slauma в
case "StrategyRules":
{
var id = Convert.ToInt32(dbChange.TablePK.Replace("StrategyRuleId=", ""));
if (dbChange.Action == "I")
{
//Model.Refresh(RefreshMode.StoreWins, Model.StrategyRules.AsEnumerable());
}
else if (dbChange.Action == "D")
{
var deletedRule1 = Model.StrategyRules.SingleOrDefault(sr => sr.Id == id);
//the above one is NULL as expected
var deletedRule2 = _strategy.StrategyRules.SingleOrDefault(sr => sr.Id == id);
//but this one is not NULL - very strange, because _strategy is in the same context
//_strategy = Model.Strategies.FirstOrDefault(st => st.StrategyId == 224);
}
}
Прежде всего большое спасибо за объяснение. Это имеет смысл, и вы правы, мне не нужно вызывать Refresh (получилось такое же поведение без него), но как вы это объясните: Model.StrategyRules.SingleOrDefault (sr => sr.Id == myId) имеет значение null после того, как DB delete, но _strategy.StrategyRules.SingleOrDefault (sr => sr.Id == myId) в не null (он по-прежнему содержит правило «удалено»). В основном _strategy.StrategyRules.Count = 7, но Model.StrategyRules.ToList() возвращает 6 элементов. Так ли это удаление из контекста или нет? Я добавлю больше кода утром, чтобы сделать его более ясным. – Novitzky
Во-вторых, приятное предложение с корпусом «D» с коммутационным футляром, но у меня нет объекта _strategy. (это только пример). Также я не могу делать Model.Strategies.SingleOrDefault (s => s.Id == ???); так как не знаю StrategyId (только StrategyRuleId). Я думал о создании объекта стратегии, вызывая Model.StrategyRules.SingleOrDefault (sr => sr.Id == myID) .Strategy, но он не работает, поскольку StrategyRule имеет значение null (уже удалено из контекста). – Novitzky
@Novitzky: К вашему первому комментарию. Исключенное правило ** не ** удаляется из контекста. 'Model.StrategyRules.ToList()' запрашивает базу данных, а не записи контекста. Таким образом, он возвращает все, кроме уже удаленного правила -> count = 6. '_strategy.StrategyRules' является графиком объекта в памяти, и у него все еще есть удаленное правило -> count = 7. – Slauma