web-dev-qa-db-fra.com

Recharger une entité et toutes les associations de propriétés de navigation - DbSet Entity Framework

J'ai un problème avec l'actualisation de l'association d'entité. Quand j'obtiens une entité avec ceci:

MyContext context = new MyContext();

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

J'ai obtenu une personne avec une association nommée Adresse et une propriété nommée Nom. Si je modifie manuellement les données dans la base de données par exemple la propriété Nom, je dois utiliser le code suivant pour recharger mon entité:

context.Entry(myPerson).Reload();

et j'ai la nouvelle valeur pour Nom. Mais si je fais de même pour Address, cela ne fonctionne pas. Je pense que c'est parce que l'adresse est une propriété de l'association. J'ai besoin de le rafraîchir.

Comment puis-je faire pour forcer le rechargement de l'association d'adresse (et de toutes les autres associations de la classe Personne)?

ÉDITER:

Dans le même cas, une personne peut avoir plusieurs adresses.

MyContext context = new MyContext();

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

Dans ce cas, ce n'est pas une référence:

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

mais une collection:

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

Je dois l'utiliser pour travailler:

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

Mais cela ne semble pas être une bonne solution pour cela pour toutes mes propriétés de navigation!

31
Sam

Si vous n'utilisez pas le chargement différé, vous devez charger explicitement le nouveau Address (comme vous avez dû le charger explicitement (avec Include, par exemple), lorsque vous avez chargé le Person initialement):

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

Si vous utilisez le chargement différé, vous n'avez pas besoin du deuxième bloc de code. Néanmoins, vous obtenez une nouvelle requête dans la base de données dès que vous accédez aux propriétés du nouveau myPerson.Address (comme si vous aviez une nouvelle requête dans le deuxième bloc de code ci-dessus) car la première ligne marquera la propriété de navigation comme non chargée si la personne fait référence à une nouvelle adresse dans la base de données.

Ce comportement ne dépend pas si vous avez exposé la clé étrangère dans la classe de modèle ou non.

Il ne semble pas y avoir de moyen d'appeler une seule méthode magique Reload qui rechargerait et mettrait à jour le graphique d'objet entier en un seul appel (similaire comme il n'y a pas de Include unique pour charger graphique d'objet complet).

28
Slauma

Je vous remercie !

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

a fait son travail pour moi.

Si p. Adresses a perdu une entrée, elle peut être actualisée par

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

mais si elle a gagné une entrée, seule votre méthode .Load () a aidé. Merci encore!

8
Satria

Vous devez utiliser l'extension Query () pour modifier votre expression LINQ. Voici un exemple basé sur mon code personcal. Dans ce code, je recharge la collection Adresses avec la propriété de navigation AddressType associée pour l'objet myPerson et place le résultat dans 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>
2
Aleksey Timkov