Uma maneira de acelerar nossos aplicativos é adicionar uma camada de cache próxima ao nosso banco de dados. Freqüentemente escrevemos métodos auxiliares para ler dados de nosso banco de dados, serializá-los e armazená-los em nosso cache. NCache integra-se ao Entity Framework Core para armazenar em cache nossas entidades com algumas linhas de código. Vamos abordar como implementar uma estratégia de cache-aside com NCache e Núcleo do Entity Framework.
O Entity Framework Core não possui um mecanismo de cache integrado. Temos que fazer o nosso próprio. Mas, NCache tem um conjunto de métodos de extensão convenientes para armazenar facilmente os resultados de nossa consulta.
Com esta integração, aproveitamos todos os recursos de escalabilidade e replicação do NCache em nossos aplicativos Entity Framework.
Vamos criar um exemplo de ASP.NET Core 6.0 para armazenar em cache uma consulta do Entity Framework Core para mostrar os 10 filmes mais bem avaliados em um catálogo.
Como se inscrever NCache com Entity Framework Core
Antes de começar, vamos ter certeza de ter NCache instalado. Precisamos de uma edição Enterprise ou Professional.
Depois de criar um ASP.NET Core Aplicativo Web API, vamos instalar o EntityFrameworkCore.NCache Pacote NuGet. Se estivermos usando uma edição Professional, instalamos o EntityFrameworkCore.NCacheEm vez disso, pacote NuGet profissional.
Registrar NCache com Entity Framework, no arquivo Program.cs da nossa aplicação, vamos escrever,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using Alachisoft.NCache.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); builder.Services.AddDbContext(options => { var config = builder.Configuration; var connectionString = config.GetConnectionString("Default"); // Configure NCache with Entity Framework // We need a cacheId and database type NCacheConfiguration.Configure(cacheId: "demoCache", DependencyType.SqlServer); NCacheConfiguration.ConfigureLogger(); options.UseSqlServer(connectionString); }); builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); app.Run(); |
Parece um ASP normal.NET Core aplicativo que usa Entity Framework Core, exceto por dois métodos: Configure() e ConfigureLogger() de NCacheConfiguração.
Com o método Configure(), especificamos o cacheId e o tipo de banco de dados. Estamos usando demoCache, a instância de cache padrão, e DependencyType.SqlServer. Claro, devemos ler o cacheId de um arquivo de configuração.
Neste exemplo, estamos usando apenas um cacheId e um tipo de banco de dados, mas também podemos passar opções extras de configuração como novas tentativas e tempos limite.
E ConfigureLogger() configura a abstração de log subjacente do ASP.NET Core.
Como inserir e armazenar em cache os resultados do Entity Framework Core em NCache
Após o registro NCache no Entity Framework Core, estamos lendo para começar a armazenar nossos filmes em cache.
Resultados do núcleo do Entity Framework em cache
Vamos criar uma classe MoviesController para ler os 10 melhores filmes e armazená-los em cache NCache. Como isso,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
using Alachisoft.NCache.EntityFrameworkCore; using Microsoft.AspNetCore.Mvc; namespace Movies.Controllers; [ApiController] [Route("[controller]")] public class MoviesController : ControllerBase { private readonly DatabaseContext _database; public MoviesController(DatabaseContext database) { _database = database; } [HttpGet] public async Task<IEnumerable> Get() { return await _database .Movies .OrderByDescending(m => m.Rating) .ThenBy(m => m.ReleaseYear) .Take(10) .FromCacheAsync(new CachingOptions { StoreAs = StoreAs.Collection }); } } |
NCache traz novos métodos de extensão sobre os métodos existentes do Entity Framework Core.
Após uma consulta LINQ para recuperar 10 filmes classificados por classificação e ano de lançamento, adicionamos um novo método: FromCacheAsync().
FromCacheAsync()
armazena em cache o resultado de nossa consulta LINQ e o retorna. Se nosso cache não tiver esse resultado, ele vai para o banco de dados e então armazena em cache. Se não conseguirmos nos conectar ao nosso servidor de cache, NCache retornará o resultado do nosso banco de dados. Em seguida, ele continuará tentando preencher o cache com nosso resultado.
Ao usar FromCacheAsync(), passamos um parâmetro CachingOptions, informando NCache para armazenar em cache o resultado de nossa consulta como um todo, em vez de entradas separadas. Há mais opções para especificar expirações e prioridades.
FromCacheAsyn() tem uma alternativa síncrona FromCache()
. Ao contrário de sua versão assíncrona, FromCache() retorna a chave de cache do novo item como parâmetro de saída.
LoadIntoCache e FromCacheOnly
Além de FromCache() e FromCacheAsync(), NCache tem outros dois métodos: LoadIntoCache() e FromCacheOnly().
LoadIntoCache() substitui os resultados armazenados em cache em cada chamada. Funciona como FromCache() com perda de cache em cada chamada. Este método é mais adequado para dados alterados com frequência e cenários onde sempre precisamos de uma nova cópia de nossos dados.
FromCacheOnly() não chama o banco de dados subjacente. Sempre vai para o servidor de cache. FromCacheOnly() oferece suporte a funções de agregação como Sum, Min e Max. Mas, também tem algumas limitações. Por exemplo, FromCacheOnly() não oferece suporte a múltiplas projeções ou junções na expressão LINQ.
Claro, esses dois últimos métodos também possuem alternativas assíncronas.
Inserindo itens
Após armazenar em cache os resultados de nossas consultas LINQ, vamos ver como inserir itens.
No MoviesController
class, vamos escrever um novo método para adicionar um filme. Assim,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// In the same MoviesController.cs file [HttpPost] public async Task Post([FromBody] AddMovie request) { var newMovie = new Movie( name: request.Name, releaseYear: request.ReleaseYear, rating: request.Rating); _database.Movies.Add(newMovie); await _database.SaveChangesAsync(); var options = new CachingOptions { StoreAs = StoreAs.SeperateEntities }; Cache cache = _database.GetCache(); cache.Insert(newMovie, out _, options); } |
Após inserir um filme como normalmente fazemos com SaveChangesAsync(), obtemos uma referência ao nosso cache com GetCache(). Então, usando a mesma referência de objeto, inserimos um novo filme com Insert() passando CachingOptions. Também podemos passar uma prioridade, um identificador de consulta e tempos de expiração.
Quando usamos Insert() se o cache já contém um item, ele é atualizado.
Observe que inserimos o novo item em nosso cache logo após chamarmos SaveChangesAsync(), sem ir novamente ao banco de dados para recuperá-lo e depois armazená-lo em cache. Isso economiza uma viagem de ida e volta ao nosso banco de dados para cada objeto que queremos inserir.
Conclusão
É assim que podemos usar NCache em nossos aplicativos Entity Framework Core. Podemos começar a armazenar nossas entidades em cache com algumas alterações em nossas consultas LINQ existentes. Precisamos apenas estender nossa configuração do Entity Framework
e use FromCache() e suas alternativas. Neste post, armazenamos em cache e inserimos itens, mas também podemos remover itens do nosso cache por um nome de chave, identificador de consulta ou referência de objeto.
Vamos lembrar, para consultas LINQ complexas, vamos usar FromCache(). Para dados atualizados com frequência, vamos usar LoadIntoCache(). E para dados somente leitura, FromCacheOnly().
Além da estratégia de cache-aside que seguimos nesta postagem, NCache oferece suporte a outras estratégias e padrões de cache, como leitura e gravação. E se integra ao ASP.NET Core estrutura para suportar o cache do estado da sessão.
Para acompanhar o código que escrevemos neste post, verifique meu NCache Repositório de demonstração no GitHub.