Uso de Entity Framework POCO Lazy Loading con caché distribuida

Entity Framework es un motor de mapeo relacional de objetos muy popular proporcionado por Microsoft y se usa cada vez más en aplicaciones de alto tráfico. Y, muchas de estas aplicaciones de alto tráfico necesitan escalabilidad que se obtiene mediante el uso de una memoria caché distribuida en memoria. Sin embargo, en algunas situaciones, Entity Framework y la memoria caché distribuida en memoria se vuelven incompatibles. Déjame explicarte cómo.

Si usa Entity Framework con Plain Old CLR Objects (POCO) junto con su capacidad de carga diferida, Entity Framework genera dinámicamente objetos proxy que contienen el código para realizar la carga diferida. Y estas definiciones de objetos dinámicos solo existen dentro del proceso de la aplicación y, por lo tanto, no se pueden serializar para una memoria caché distribuida fuera del proceso.

Aquí hay un ejemplo de proxy que se genera para un Customer entidad en la que desea utilizar Entity Framework carga diferida para relacionados orders. Vea cómo aparece un nombre de clase generado dinámicamente. Este nombre de clase solo está disponible dentro del proceso de solicitud y sería desconocido fuera del proceso.

Usando Entity Framework POCO
Ejemplo de proxy generado por la carga diferida de Entity Framework

Ahora, el problema es que un caché distribuido siempre está fuera de proceso y requiere que serialice todos los objetos antes de almacenarlos en caché y luego es posible que estos objetos deban deserializarse en una máquina diferente cuando se accede a ellos desde otra caja de cliente. Por lo tanto, el tipo de objeto debe conocerse en ambas máquinas para fines de deserialización. Y esto no es posible con el proxy generado dinámicamente en Entity Framework porque solo se conocen dentro del proceso de aplicación en una máquina. Por lo tanto, la única forma para usted es deshabilitar la generación de proxy en Entity Framework para usarlo con un caché distribuido, pero este no es un escenario muy práctico ya que esto también compromete las capacidades de carga diferida de Entity Framework.

¿Cómo usar Entity Framework POCO Lazy Loading sin proxy?

Para superar este problema y usar Entity Framework con carga diferida, primero debe deshabilitar el proxy para que no cause problemas de serialización. Luego, debe inyectar código adicional en su aplicación para lograr la carga diferida porque si el proxy está desactivado, no hay soporte para la carga diferida en Entity Framework.

Además, debe escribir este código adicional de manera que lo ayude a lograr la funcionalidad de carga diferida de Entity Framework y, al mismo tiempo, no viole el POCO-ness de sus entidades. Discutamos este enfoque paso a paso con más detalles con un ejemplo.

Si usted tiene una Customer objeto que tiene un Orders lista en él como una propiedad, entonces la carga diferida debería funcionar de tal manera que si accede a la lista relacionada Orders para un Cliente y aún no se han cargado (lo que significa que no existen en el contexto de Entity Framework), entonces el Customer El objeto automáticamente hace una llamada para cargar información relacionada. Orders. Estoy usando este ejemplo a continuación para demostrar cómo implementar la carga diferida de Entity Framework sin proxy y también usarlos en un caché distribuido.

  1. El primer paso es desactivar la generación de proxy de Entity Framework y también desactivar la funcionalidad de carga diferida de Entity Framework. Usted mismo implementa el código de carga diferida en el siguiente paso. El context.ContextOptions.ProxyCreationEnabled La propiedad es verdadera por defecto. Debe establecerlo explícitamente en "falso" en el constructor predeterminado de su objeto de contexto para desactivar esta función.
    {
      public NorthwindContext() : base("name=NorthwindContext")
      {
        this.ContextOptions.ProxyCreationEnabled = false;
        this.ContextOptions.LazyLoadingEnabled = false;
      }
    }
    Deshabilitar la generación de proxy y la configuración de carga diferida de Entity Framework garantiza que ya no se cree un proxy dinámico y que no haya problemas de serialización con una memoria caché distribuida. Objetos CLR antiguos simples reales (POCO) Customer Entity Framework utiliza el objeto y, por lo tanto, se puede almacenar en caché y recuperar en un caché distribuido sin tener ningún problema.

  2. El siguiente paso es introducir algún código que lo ayude a lograr la carga diferida de Entity Framework para pedidos relacionados para un cliente. Como se mencionó anteriormente, este código lo ayuda a lograr el objetivo, pero también debe asegurarse de que los objetos de pedido y de cliente reales sigan siendo objetos CLR simples (POCO).

    Para esto, creas otra clase que tiene Entity framework static ObjectContext y una función que se usa para la funcionalidad de carga diferida de Entity Framework para pedidos. Esta función se llama por referencia en el objeto POCO del cliente real más adelante. Aquí está la definición de código para su clase 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. Ahora necesita actualizar el Customer object para que tenga la capacidad de Entity Framework de cargar de forma diferida todos los pedidos relacionados para un cliente. Así es como actualiza el objeto Cliente y los captadores de la lista de Pedidos para llamar a esta funcionalidad por referencia. Todavía necesita configurar el OrderLazyLoad método para señalar la función de carga diferida definida en la clase Helper, que se realiza en el siguiente paso en su programa 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. Ahora necesita cambiar su programa real para usar esta funcionalidad extendida.
    1. Estableces el contexto del objeto en la clase auxiliar. CustomerHelper.CurrentContext) debe ser el mismo que se usa en el programa principal para que todas las entidades se carguen bajo el mismo contexto de objeto, es decir, está usando el mismo contexto de objeto en el programa de consumo, así como en la función definida en la clase de ayuda para la carga diferida.
      NorthwindContext Context = new NorthwindContext();
      CustomerHelper.CurrentContext = Context;
    2. También configura el OrderLazyLoad método para apuntar a la función de carga diferida del asistente. Este es un lugar más apropiado para hacer esto ya que no desea que su Customer object para referirse directamente al objeto de la clase Helper.
      Customer.OrderLazyLoad = Helper.CustomerHelper.DoLazyLoading;
  5. Ejecute el programa donde puede consultar a los clientes y luego también almacenarlos en un caché distribuido y también ver pedidos relacionados con el soporte adicional de la carga diferida de Entity Framework. Cada vez que su programa acceda a la Orders de un Customer, también se llama a la funcionalidad de carga diferida inducida.
    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();
    }

Resumen

He discutido un enfoque para usar un caché distribuido para almacenar en caché objetos CLR antiguos simples (POCO) usados ​​en Entity Framework sin tener que preocuparse por el problema de serialización y aún así poder tener la funcionalidad completa de la carga diferida de Entity Framework. Aunque este enfoque implica escribir algo de código para lograr una carga diferida, en esencia tiene los beneficios del almacenamiento en caché distribuido, como el alto rendimiento, la escalabilidad y la confiabilidad en una aplicación de Entity Framework.

© Copyright Alachisoft 2002 - Todos los derechos reservados. NCache es una marca registrada de Diyatech Corp.