Перезагрузите сущность и всю Ассоциацию навигационных свойств - DbSet Entity Framework
У меня проблема с обновлением ассоциации сущностей. Когда я получаю объект с таким именем:
MyContext context = new MyContext();
Person myPerson = context.PersonSet.FirstOrDefault();
String myPersonName = myPerson.Name;
Address myPersonAddress = myPerson.Address;
У меня есть человек с ассоциацией с именем Address и именем Name. Если я вручную изменяю данные в базе данных, например, имя свойства, я должен использовать следующий код для перезагрузки моего объекта:
context.Entry(myPerson).Reload();
и у меня есть новое значение для Name. Но если я делаю то же самое для адреса, это не сработает. Я думаю, это потому, что Адрес является свойством ассоциации. Мне нужно обновить его.
Как сделать, чтобы принудительно перезагрузить ассоциацию адресов (и все остальные ассоциации в классе 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();
Но это не кажется хорошим решением для всех моих свойств навигации!
Ответы
Ответ 1
Если вы не используете ленивую загрузку, вы явно загружаете новый 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
для загрузки полной диаграммы объекта).
Ответ 2
Для изменения выражения LINQ вам нужно использовать расширение Query(). Здесь это пример на основе моего персонального кода. В этом коде я повторно загружаю коллекцию Адресов с соответствующим свойством navigationType для объекта 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>
Ответ 3
Спасибо!
context.Entry(myPerson).Collection(p => p.Addresses).Load();
сделал свою работу для меня.
Если p.Addresses потерял одну запись, ее можно обновить с помощью
((IObjectContextAdapter)CurrentContext(context)).ObjectContext.Refresh(RefreshMode.StoreWins, p.Addresses);
но если он получил одну запись, помог только ваш метод .Load(). Еще раз спасибо!
Ответ 4
Я решил эту проблему с помощью Detach перед чтением объекта из dbContext.
Этот метод позволил мне обновить все навигационные свойства объекта.
Я описал свой сценарий и подробности решения здесь
Entity Framework: перезагрузить вновь созданный объект/Обновить свойства навигации