Перезагрузите сущность и всю ассоциацию свойств навигации - DbSet Entity Framework - PullRequest
29 голосов
/ 31 января 2012

У меня проблема с обновлением ассоциации сущностей. Когда я получаю сущность с таким:

MyContext context = new MyContext();

Person myPerson = context.PersonSet.FirstOrDefault();
String myPersonName = myPerson.Name;
Address myPersonAddress = myPerson.Address;

У меня есть человек с ассоциацией по имени Адрес и свойством по имени. Если я вручную изменяю данные в базе данных, например, свойство Name, я должен использовать следующий код для перезагрузки моей сущности:

context.Entry(myPerson).Reload();

и у меня есть новое значение для имени. Но если я сделаю то же самое для адреса, это не сработает. Я думаю, что это потому, что Адрес является собственностью ассоциации. Мне нужно обновить это.

Как мне сделать принудительную перезагрузку ассоциации адресов (и всех других ассоциаций в классе Person)?

EDIT:

В этом же случае у человека может быть несколько адресов.

MyContext context = new MyContext();

Person myPerson = context.PersonSet.FirstOrDefault();
String myPersonName = myPerson.Name;
List<Address> myPersonAddresses = myPerson.Addresses;

В данном случае это не ссылка:

context.Entry(myPerson).Reference(p => p.Address).Load();
// Address will be populated with only the new address
// this isn't required because I use lazy loading

но коллекция:

context.Entry(myPerson).Collection(p => p.Addresses).Load();
// Address will be populated with old value and new value

Мне нужно использовать это для работы:

context.Entry(myPerson).Collection(p => p.Addresses).CurrentValue.Clear();
context.Entry(myPerson).Collection(p => p.Addresses).Load();

Но, похоже, это не лучшее решение для всех моих навигационных свойств!

Ответы [ 4 ]

28 голосов
/ 31 января 2012

Если вы не используете отложенную загрузку, у вас есть загрузка новой Address явно (как вы должны были загрузить ее явно (например, с Include), когда вы загрузили Person изначально):

context.Entry(myPerson).Reload();
// If the person refers to another Address in the DB
// myPerson.Address will be null now

if (myPerson.Address == null)
    context.Entry(myPerson).Reference(p => p.Address).Load();
    // myPerson.Address will be populated with the new Address now

Если вы используете отложенную загрузку, вам не нужен второй блок кода. Тем не менее, вы получаете новый запрос к базе данных, как только вы получаете доступ к свойствам нового myPerson.Address (например, у вас есть новый запрос во втором блоке кода выше), потому что первая строка помечает свойство навигации как не загруженное, если человек ссылается на новый адрес в БД.

Это поведение не зависит от того, выставили ли вы внешний ключ в классе модели или нет.

Похоже, нет способа вызвать какой-то один магический метод Reload, который бы перезагрузил и обновил весь граф объектов за один вызов (похоже, что не существует единственного Include для загрузки полного графа объектов ).

8 голосов
/ 29 июля 2016

Спасибо!

context.Entry(myPerson).Collection(p => p.Addresses).Load();

сделал свою работу за меня.

Если p.Addresses потеряли одну запись, она может быть обновлена ​​на

((IObjectContextAdapter)CurrentContext(context)).ObjectContext.Refresh(RefreshMode.StoreWins, p.Addresses);

, ноесли он получил одну запись, помог только ваш метод .Load ().Еще раз спасибо!

2 голосов
/ 04 сентября 2012

Вам нужно использовать расширение Query () , чтобы изменить выражение LINQ. Вот это пример на основе моего личного кода. В этом коде я перезагружаю коллекцию адресов с соответствующим свойством навигации AddressType для объекта myPerson и помещаю результат в SomeList:

_DbContext.Entry<Person>(myPerson)
          .Collection(i => i.Adresses) // navigation property for Person
          .Query()
          .Include("AddressType")        // navigation property for Address
          .OrderBy(i => i.Name)
          .ThenBy(i => i.AddressType.AddressTypeName) // just an example
          .Select(i => new someClass
          {
              SoomeField1 = i.SomeField1,
              ...
          })
          .ToList()
          .ForEach(i => SomeList.Add(i)); // SomeList is a List<T>
0 голосов
/ 30 сентября 2015

Я решил эту проблему с помощью Detach перед чтением объекта из dbContext. Этот метод позволил мне обновить все навигационные свойства объекта. Я описал свой сценарий и детали решения здесь Entity Framework: перезагрузка вновь созданного объекта / перезагрузка свойств навигации

...