web-dev-qa-db-fra.com

Problème de mise en cache du cadre d'entité

Je suis nouveau dans Entity Framework.

J'ai accès à certaines valeurs de ma base de données en utilisant EF. Il retourne parfaitement et les valeurs sont affichées dans les étiquettes. Mais lorsque je supprime toutes les valeurs de ma table (sans utiliser EF), la requête EF renvoie mes anciennes valeurs. Je sais que l'EF stocke les valeurs dans le cache et renvoie les données mises en cache pour les exécutions suivantes. Est-ce correct? 

Alors, comment puis-je résoudre le problème lorsque j'ai supprimé toutes les valeurs de ma base de données, alors que EF renvoie les anciennes valeurs?

Modifier :

Maintenant, j'ai utilisé datamodel.SaveChanges(). Mais maintenant, cela renvoie aussi les anciennes valeurs.

Mon exemple de requête ressemble à ce qui suit:

SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities();
datamodel.SaveChanges();
List<Compliance> compliance=new List<Compliance>();
IList<ComplianceModel> complianceModel;
if (HttpContext.Current.User.IsInRole("SuperAdmin"))
{
    compliance = datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList();
}
47
Ramesh Rajendran

Si vous savez que des modifications ont eu lieu en dehors de EF et souhaitez actualiser votre ctxt pour une entité spécifique, vous pouvez appeler ObjectContext.Refresh

datamodel.Refresh(RefreshMode.StoreWins, orders);

Si cela semble être une occurrence courante, vous devez désactiver la mise en cache des objets dans vos requêtes:

SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities();
datamodel.tblCities.MergeOption = MergeOption.NoTracking; 

ou pour désactiver la mise en cache au niveau objet pour une entité spécifique,

Context.Set<Compliances>().AsNoTracking();
35
Dave Alperovich

Lorsque vous utilisez EF, il charge par défaut chaque entité une fois par contexte . La première requête crée une instance d'entité et la stocke en interne. Tout la requête suivante qui nécessite une entité avec la même clé renvoie this instance stockée. Si les valeurs dans le magasin de données ont changé, vous recevez toujours l'entité avec les valeurs de la requête initiale

Une réponse prudente:

https://stackoverflow.com/a/3653392/1863179

27
Morteza

EF ne chargera pas les modifications sauf si vous interrogez le contexte. EF interroge la base de données et charge les mappe dans des objets. Il surveille les modifications apportées aux objets et non à la base de données. EF ne suit pas les modifications apportées directement à la base de données et ne suivra jamais.

Vous avez chargé une liste, cette liste est votre cache en mémoire. Même en appelant Enregistrer les modifications, l'actualisation ne sera pas effectuée. Vous devrez interroger le contexte une fois de plus, c'est-à-dire créer une nouvelle liste.

Pour voir les changements, vous devrez exécuter la ligne suivante une fois de plus,

datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList()
20
Akash Kava

Je pense que vous devriez suivre certaines des autres solutions ici, mais il semble que vous vouliez vider le cache. Vous pouvez y parvenir en procédant comme suit:

var count = datamodel.Compliances.Local.Count; // number of items in cache (ex. 30)

datamodel.Compliances.Local.ToList().ForEach(c => {
    datamodel.Entry(c).State = EntityState.Detached;
});

count = datamodel.Compliances.Local.Count; // 0
7
David Sherret

Le code ci-dessous a aidé mon objet à être actualisé avec de nouvelles valeurs de base de données. La commande Entry (object) .Reload () oblige l’objet à rappeler les valeurs de la base de données.

GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload();
4
HGMamaci

Je vous recommande d'utiliser certains MergeOption à tous les EntitieSet après avoir créé le contexte, comme ceci:

var objSetProps = ctx.GetType().GetProperties().Where(prop => prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(ObjectSet<>));
foreach (PropertyInfo objSetProp in objSetProps)
{
    ObjectQuery objSet = (ObjectQuery)objSetProp.GetValue(ctx, BindingFlags.GetProperty, null, null, null);
    objSet.MergeOption = MergeOption.PreserveChanges;
}

Lisez à propos de MergeOption ici: http://msdn.Microsoft.com/en-us/library/system.data.objects.mergeoption.aspx Vous utiliserez NoTracking, je pense.

Mais, vous voulez effacer les entités "mises en cache", en les détachant.

var entidades = Ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged);
foreach (var objectStateEntry in entidades)
    Ctx.Detach(objectStateEntry.Entity);

Où les Ctx sont mon contexte.

4
Tiago Gouvêa

Je pense que ce dont vous avez besoin est GetDatabaseValues(). Il s'utilise comme:

context.Entry(/*your entry*/).GetDatabaseValues();

Les informations ci-dessous proviennent de msdn :

Les valeurs actuelles sont les valeurs que les propriétés de l'entité contient actuellement. Les valeurs d'origine sont les valeurs qui ont été lues de la base de données lorsque l'entité a été interrogée. Les valeurs de la base de données sont les valeurs telles qu'elles sont actuellement stockées dans la base de données. Obtenir le Les valeurs de la base de données sont utiles lorsque les valeurs de la base de données peuvent avoir changé depuis l’interrogation de l’entité, par exemple lors d’une édition simultanée en la base de données a été créée par un autre utilisateur.

2
Adil Mammadov

Je soupçonne que le problème sous-jacent ici est que votre DbContext traîne trop longtemps. D'après le fait que vous utilisez HttpContext, vous disposez d'une application Web et de consignes générales pour l'utilisation de DbContext include 

Lorsque vous travaillez avec des applications Web, utilisez une instance de contexte par demande.

Si vous utilisez MVC, vous pouvez utiliser le modèle Dispose de votre contrôleur comme suit:

public class EmployeeController : Controller
{
    private EmployeeContext _context;

    public EmployeeController()
    {
        _context = new EmployeeContext();
    }

    public ActionResult Index()
    {
        return View(_context.Employees.ToList());
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _context.Dispose();
        }
        base.Dispose(disposing);
    }
}

Mais vous devriez vraiment regarder l'injection de dépendance pour gérer la durée de vie de DbContext

2
Colin

Premièrement, je ne suggérerais pas de modifier la base de données externe à votre système à moins que vous ne fassiez que des tests et du développement.

EF DbContext contient une interface IDisposable. Pour libérer les données mises en cache, effectuez les appels Dispose manuellement ou placez votre objet de base de données dans un bloc using.

        using (SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities())
        {
            List<Compliance> compliance = new List<Compliance>();
            IList<ComplianceModel> complianceModel;
            if (HttpContext.Current.User.IsInRole("SuperAdmin"))
            {
                compliance = datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList();
            }
        }

Cela garantira que le contexte est effacé et recréé lors de sa prochaine utilisation. Assurez-vous de le faire pour tous vos appels et pas seulement pour ceux avec lesquels vous rencontrez des problèmes.

2

Dans mon cas, c'était une mauvaise chaîne de connexion. Entity semblait aller très bien car il ne s'est jamais plaint jusqu'à ce que je mette le contexte en contexte et que le message d'erreur me soit finalement arrivé.

0
Michael

Couple de choses que vous pouvez faire. 

  1. Utilisez un nouveau contexte. Les entités mises en cache sont stockées dans le contexte. L'utilisation d'un nouveau contexte l'empêche d'utiliser le cache.
  2. Si vous voulez vraiment un contexte global/durable, vous avez deux sous-options: A.) Appelez toujours la méthode Reload. db.Entry (entity) .Reload () ... ceci force le contexte à recharger cette entité . b.) utilise un objet SqlDependency pour détecter le moment où les enregistrements sont modifiés et recharger les entités si nécessaire https://code.msdn.Microsoft.com/How-to-use-SqlDependency-5c0da0b3
0
Marc Johnston