Usando o carregamento lento do Entity Framework POCO com cache distribuído

O Entity Framework é um mecanismo de mapeamento objeto-relacional muito popular fornecido pela Microsoft e está sendo cada vez mais usado em aplicativos de alto tráfego. E muitos desses aplicativos de alto tráfego precisam de escalabilidade que vem usando um cache distribuído na memória. No entanto, em algumas situações, o Entity Framework e o cache distribuído na memória se tornam incompatíveis. Deixe-me explicar como.

Se você estiver usando o Entity Framework com POCO (Plain Old CLR Objects) juntamente com seu recurso de carregamento lento, o Entity Framework gera dinamicamente objetos proxy que contêm o código para fazer o carregamento lento. E essas definições de objetos dinâmicos só existem dentro do processo do aplicativo e, portanto, não podem ser serializadas para um cache distribuído fora do processo.

Aqui está um exemplo de proxy sendo gerado para um Customer entidade onde você deseja usar o carregamento lento do Entity Framework para orders. Veja como um nome de classe gerado dinamicamente aparece. Esse nome de classe só está disponível no processo de inscrição e seria desconhecido fora do processo.

Usando o Entity Framework POCO
Exemplo de proxy sendo gerado pelo carregamento lento do Entity Framework

Agora, o problema é que um cache distribuído está sempre fora de processo e exige que você serialize todos os objetos antes de armazená-los em cache e, em seguida, esses objetos podem precisar ser desserializados em uma máquina diferente quando são acessados ​​de outra caixa de cliente. Portanto, o tipo de objeto deve ser conhecido em ambas as máquinas para fins de desserialização. E isso não é possível com o proxy gerado dinamicamente no Entity Framework porque eles são conhecidos apenas dentro do processo do aplicativo em uma máquina. Portanto, a única maneira para você é desabilitar a geração de proxy no Entity Framework para usá-lo com um cache distribuído, mas esse não é um cenário muito prático, pois isso também compromete os recursos de carregamento lento do Entity Framework.

Como usar o Entity Framework POCO Lazy Loading sem proxy?

Para superar esse problema e usar o Entity Framework com carregamento lento, primeiro você precisa desabilitar o proxy para que ele não cause problemas de serialização. Em seguida, você precisa injetar algum código adicional em seu aplicativo para obter o carregamento lento porque, se o proxy estiver desativado, não haverá suporte para carregamento lento no Entity Framework.

Além disso, você deve escrever esse código adicional de forma que ele ajude a obter a funcionalidade de carregamento lento do Entity Framework e, ao mesmo tempo, não viole o POCO-ness de suas entidades. Vamos discutir essa abordagem passo a passo em mais detalhes com um exemplo.

Se você tem um Customer objeto que possui um Orders list nele como uma propriedade, o carregamento lento deve funcionar de tal forma que, se você acessar o relacionado Orders para um Cliente e eles ainda não foram carregados (o que significa que não existem no contexto do Entity Framework), então o Customer objeto faz automaticamente uma chamada para carregar relacionado Orders. Estou usando o exemplo abaixo para demonstrar como implementar o carregamento lento do Entity Framework sem proxy e também usá-los em um cache distribuído.

  1. A primeira etapa é desativar a geração de proxy do Entity Framework e também desativar a funcionalidade de carregamento lento do Entity Framework. Você mesmo implementa o código de carregamento lento na próxima etapa. A context.ContextOptions.ProxyCreationEnabled propriedade é verdadeira por padrão. Você precisa defini-lo explicitamente como "false" no construtor padrão do seu objeto de contexto para desativar esse recurso.
    {
      public NorthwindContext() : base("name=NorthwindContext")
      {
        this.ContextOptions.ProxyCreationEnabled = false;
        this.ContextOptions.LazyLoadingEnabled = false;
      }
    }
    Desabilitar a geração de proxy e as configurações de carregamento lento do Entity Framework garante que o proxy dinâmico não seja mais criado e que não haja nenhum problema de serialização com um cache distribuído. Objetos CLR antigos simples reais (POCO) Customer object é usado pelo Entity framework e, portanto, pode ser armazenado em cache e recuperado em um cache distribuído sem problemas.

  2. A próxima etapa é apresentar algum código que ajude você a obter o carregamento lento do Entity Framework para pedidos relacionados para um cliente. Como mencionado acima, esse código ajuda você a atingir o objetivo, mas também deve garantir que os objetos reais do cliente e do pedido ainda permaneçam como Objetos CLR antigos (POCO).

    Para isso, você cria outra classe que possui Entity framework estático ObjectContext e uma função que é usada para a funcionalidade de carregamento lento do Entity Framework para pedidos. Essa função é chamada por referência no objeto POCO do cliente real posteriormente. Aqui está a definição de código para sua 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. Agora você precisa atualizar o Customer objeto para que ele tenha a capacidade do Entity Framework de carregar lentamente todos os pedidos relacionados para um cliente. Aqui está como você atualiza o objeto Customer e os getters da lista de pedidos para chamar essa funcionalidade por referência. Você ainda precisa definir o OrderLazyLoad método para apontar para a função de carregamento lento definida na classe Helper, que é feita na próxima etapa em seu 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. Agora você precisa alterar seu programa real para usar essa funcionalidade estendida.
    1. Você define o contexto do objeto na classe auxiliar CustomerHelper.CurrentContext) para ser o mesmo usado no programa principal para que todas as entidades sejam carregadas no mesmo contexto de objeto, ou seja, você está usando o mesmo contexto de objeto no programa consumidor, bem como na função definida na classe auxiliar para carregamento lento.
      NorthwindContext Context = new NorthwindContext();
      CustomerHelper.CurrentContext = Context;
    2. Você também define o OrderLazyLoad método para apontar para a função de carregamento lento do Helper. Este é o local mais apropriado para fazer isso, pois você não quer que seu Customer object para se referir diretamente ao objeto da classe Helper.
      Customer.OrderLazyLoad = Helper.CustomerHelper.DoLazyLoading;
  5. Execute o programa onde você pode consultar clientes e, em seguida, armazená-los em um cache distribuído e também ver pedidos relacionados com o suporte adicional do carregamento lento do Entity Framework. Cada vez que seu programa acessa o Orders a partir de um Customer, a funcionalidade de carregamento lento induzido também é chamada.
    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();
    }

Resumo

Discuti uma abordagem para usar um cache distribuído para armazenar em cache Plain Old CLR Objects (POCO) usado no Entity Framework sem ter que se preocupar com o problema de serialização e ainda poder ter a funcionalidade completa do carregamento lento do Entity Framework. Embora essa abordagem envolva escrever algum código para obter carregamento lento, mas, em essência, você tem os benefícios do cache distribuído, como alto desempenho, escalabilidade e confiabilidade em um aplicativo de estrutura de entidade.

© Copyright Alachisoft 2002 - . Todos os direitos reservados. NCache é uma marca registrada da Diyatech Corp.