Utilisation du chargement différé Entity Framework POCO avec cache distribué

Entity Framework est un moteur de mappage objet-relationnel très populaire fourni par Microsoft et est de plus en plus utilisé dans les applications à fort trafic. De plus, bon nombre de ces applications à fort trafic nécessitent une évolutivité qui vient de l'utilisation d'un cache distribué en mémoire. Cependant, dans certaines situations, Entity Framework et le cache distribué en mémoire deviennent incompatibles. Laissez-moi vous expliquer comment.

Si vous utilisez Entity Framework avec Plain Old CLR Objects (POCO) avec sa capacité de chargement différé, Entity Framework génère dynamiquement des objets proxy qui contiennent le code pour effectuer le chargement différé. De plus, ces définitions d'objets dynamiques n'existent que dans le processus d'application et ne peuvent donc pas être sérialisées pour un cache distribué hors processus.

Voici un exemple de proxy généré pour un Customer entité où vous souhaitez utiliser le chargement différé Entity Framework pour les orders. Voyez comment un nom de classe généré dynamiquement apparaît. Ce nom de classe n'est disponible que dans le processus de candidature et serait inconnu en dehors du processus.

Utiliser Entity Framework POCO
Exemple de proxy généré par le chargement différé d'Entity Framework

Maintenant, le problème est qu'un cache distribué est toujours hors processus et vous oblige à sérialiser tous les objets avant de les mettre en cache, puis ces objets peuvent devoir être désérialisés sur une autre machine lorsqu'ils sont accessibles à partir d'un autre boîtier client. Par conséquent, le type d'objet doit être connu sur les deux machines à des fins de désérialisation. Et cela n'est pas possible avec un proxy généré dynamiquement dans Entity Framework car ils ne sont connus que dans le processus d'application sur une seule machine. Ainsi, la seule façon pour vous est de désactiver la génération de proxy dans Entity Framework afin de l'utiliser avec un cache distribué, mais ce n'est pas un scénario très pratique car cela compromet également les capacités de chargement différé d'Entity Framework.

Comment utiliser Entity Framework POCO Lazy Loading sans proxy ?

Afin de surmonter ce problème et d'utiliser Entity Framework avec un chargement différé, vous devez tout d'abord désactiver le proxy afin qu'il ne cause aucun problème de sérialisation. Vous devez ensuite injecter du code supplémentaire dans votre application pour réaliser vous-même le chargement paresseux, car si le proxy est désactivé, le chargement paresseux n'est pas pris en charge dans Entity Framework.

En outre, vous devez écrire ce code supplémentaire de manière à ce qu'il vous aide à atteindre la fonctionnalité de chargement paresseux d'Entity Framework et en même temps, il ne viole pas la POCO-ness de vos entités. Discutons de cette approche étape par étape plus en détail avec un exemple.

Si vous avez un Customer objet qui a un Orders listez-le en tant que propriété, le chargement paresseux devrait fonctionner de telle manière que si vous accédez au fichier associé Orders pour un client et qu'ils n'ont pas encore été chargés (ce qui signifie qu'ils n'existent pas dans le contexte Entity Framework), alors le Customer l'objet effectue automatiquement un appel pour charger les éléments associés Orders. J'utilise cet exemple ci-dessous pour montrer comment implémenter le chargement paresseux d'Entity Framework sans proxy et également les utiliser dans un cache distribué.

  1. La première étape consiste à désactiver la génération de proxy Entity Framework et également à désactiver la fonctionnalité de chargement différé d'Entity Framework. Vous implémentez vous-même le code de chargement différé à l'étape suivante. Les context.ContextOptions.ProxyCreationEnabled propriété est true par défaut. Vous devez le définir explicitement sur "false" dans le constructeur par défaut de votre objet de contexte afin de désactiver cette fonctionnalité.
    {
      public NorthwindContext() : base("name=NorthwindContext")
      {
        this.ContextOptions.ProxyCreationEnabled = false;
        this.ContextOptions.LazyLoadingEnabled = false;
      }
    }
    La désactivation de la génération de proxy et des paramètres de chargement différé d'Entity Framework garantit que le proxy dynamique n'est plus créé et qu'il n'y a plus de problème de sérialisation avec un cache distribué. Objets CLR anciens bruts réels (POCO) Customer L'objet est utilisé par Entity Framework et peut donc être mis en cache et récupéré dans un cache distribué sans aucun problème.

  2. L'étape suivante consiste à introduire du code qui vous aide à réaliser le chargement différé d'Entity Framework pour les commandes associées d'un client. Comme mentionné ci-dessus, ce code vous aide à atteindre l'objectif, mais il doit également garantir que les objets client et commande réels restent toujours des objets CLR ordinaires (POCO).

    Pour cela, vous créez une autre classe qui a Entity framework static ObjectContext et une fonction utilisée pour la fonctionnalité de chargement différé d'Entity Framework pour les commandes. Cette fonction est appelée ultérieurement par référence dans l'objet POCO client réel. Voici la définition de code pour votre classe Helper.


    namespace Helper
      {
          public class CustomerHelper
              {
                  public static NorthwindContext CurrentContext;
                  static public void DoLazyLoading(Customer customer, List<Order> orders)
                      {
                          if (CurrentContext == null) return; //no lazy loading
                          var query = from o in CurrentContext.Orders where o.CustomerID == customer.CustomerID select o;
                  
                  foreach (Order o in query)
                          { orders.Add(o); }
                    }
                }
    }
  3. Vous devez maintenant mettre à jour le Customer objet afin qu'il ait la capacité d'Entity Framework de charger paresseusement toutes les commandes associées pour un client. Voici comment mettre à jour l'objet Customer et les accesseurs de liste Orders pour appeler cette fonctionnalité par référence. Vous devez encore régler le OrderLazyLoad méthode pour pointer vers la fonction de chargement paresseux définie dans la classe Helper, ce qui est fait à l'étape suivante de votre programme principal.
    namespace MyPOCOs
    {
      [Serializable]
      public class Customer
      {
        public string CustomerID { get; set; }
        public string CompanyName { get; set; }
        public static Action < Customer, List < Order >> OrderLazyLoad = null;
    
        private List < Order > orders; 
        public virtual List< Order > Orders
        {
          get
          {
            if (orders == null)
            {
              orders = new List < Order >();
              OrderLazyLoad(this, orders);
            }
            return orders;
          }
          set
          {
            orders = value;
          }
        }
      }
      [Serializable]
      public class Order…
    }
  4. Vous devez maintenant modifier votre programme actuel pour utiliser cette fonctionnalité étendue.
    1. Vous définissez le contexte de l'objet dans la classe d'assistance CustomerHelper.CurrentContext) être le même que celui utilisé dans le programme principal afin que toutes les entités soient chargées dans le même contexte d'objet, c'est-à-dire que vous utilisez le même contexte d'objet dans le programme consommateur ainsi que dans la fonction définie dans la classe d'assistance pour le chargement différé.
      NorthwindContext Context = new NorthwindContext();
      CustomerHelper.CurrentContext = Context;
    2. Vous définissez également le OrderLazyLoad méthode pour pointer vers la fonction de chargement paresseux de Helper. C'est un endroit plus approprié pour le faire car vous ne voulez pas que votre Customer objet pour faire référence directement à l'objet de la classe Helper.
      Customer.OrderLazyLoad = Helper.CustomerHelper.DoLazyLoading;
  5. Exécutez le programme où vous pouvez interroger les clients, puis les mettre en cache dans un cache distribué et également voir les commandes associées avec la prise en charge supplémentaire du chargement différé d'Entity Framework. Chaque fois que votre programme accède au Orders d'un Customer, la fonctionnalité de chargement différé induit est également appelée.
    static void Main(string[] args)
    {
      Cache mycache = NCache.InitializeCache("mycache");        
      NorthwindContext Context = new NorthwindContext();
      CustomerHelper.CurrentContext = Context;
      Customer.OrderLazyLoad = Helper.CustomerHelper.DoLazyLoading;
    
      var query = from c in Context.Customers where c.CompanyName.StartsWith("b") select c;
      foreach (Customer c in query)
      {
        mycache.Insert(c.CustomerID, c);
        Console.WriteLine("{0}", c.CustomerID);
        foreach (Order order in c.Orders)
        {
          Console.WriteLine("\t{0}", order.OrderDate.ToString());
        }
      }
      Console.ReadLine();
    }

Résumé

J'ai discuté d'une approche permettant d'utiliser un cache distribué pour la mise en cache des objets POCO (Plain Old CLR Objects) utilisés dans Entity Framework sans avoir à se soucier du problème de sérialisation tout en pouvant bénéficier de toutes les fonctionnalités du chargement paresseux d'Entity Framework. Bien que cette approche implique l'écriture de code pour obtenir un chargement paresseux, vous bénéficiez essentiellement des avantages de la mise en cache distribuée, tels que des performances, une évolutivité et une fiabilité élevées dans une application Entity Framework.

© Copyright Alachisoft 2002 - . Tous droits réservés. NCache est une marque déposée de Diyatech Corp.