Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Uma estratégia para evitar de ir tanto ao banco

Tenho muitas tabelas auxiliares com, por exemplo, nomes de cidades.

Como esse tipo de tabela sofre inserção de novos itens no começo mas depois passa não sofrer mais alterações com frequência, pensei em carregar o conteúdo em SelectLists e armazenar essas listas em Session.

Assim, eu teria listas já carregadas na memória e só atualizaria essas listas se houvesse o cadastro de um novo ítem na tabela.

É uma boa estratégia? Tem algum inconveniente?

Então eu fiz um DAO que carrega a lista de Cidades:

public SelectList ListaParaDropDown()
        {
            var cidades = db.Cidades
            .Select(u => new
            {
                Text = u.Nome + " (" + u.Estado + ")",
                Value = u.ID

            }).ToList();

            SelectList lista = new SelectList(cidades.OrderBy(x => x.Text), "Value", "Text");

            return lista;
        }

E o resultado desse método vai para a Session já na entrada do Sistema:

public void CarregarListasGlobais()
 {
      Session["ListaCidades"] = new CidadesDAO().ListaParaDropDown();

Funcionou, mas tive um problema que reside no fato de que em telas de EDIÇÃO, eu precisaria selecionar o registro já escolhido anteriormente e que está gravado.

E parece que não há uma forma de setar o SelectedValue a não ser na montagem do SelectList. E para isso eu teria de ir ao banco novamente e fazer um :

public SelectList ListaParaDropDown(int? id)
        {
            var cidades = db.Cidades
            .Select(u => new
            {
                Text = u.Nome + " (" + u.Estado + ")",
                Value = u.ID

            }).ToList();

            SelectList lista = new SelectList(cidades.OrderBy(x => x.Text), "Value", "Text", id);

            return lista;
        }

E praticamente não valeria a pena todo esse esforço.

Tentei pegar a lista já criada da Session e setar o Valor Selecionado dela usando:

lista.SelectedValue(id);

mas não funciona mesmo havendo esse método no SelectList.

Alguma sugestão???

2 respostas
solução!

Olá Jaqueline,

você pode até guardar a lista de cidades na sessão, o problema é que cada usuário do sistema tem 1 sessão para ele. Imagina que você tem 100 cidades cadastradas no seu sistema e existem 500 usuários logados neste instante (ou seja, 500 sessões abertas). Assim, na sua memória ele está guardando 50000 objetos Cidade só para que cada sessão de cada usuário tenha esta lista. Fora que se você atualizar a tabela de cidades, terá que atualizar 500 sessões diferentes.

No seu caso, o que você quer fazer de poupar a parte da consulta da lista de cidades dado que ela não muda com frequência e todos usam a mesma lista é o que conhecemos como cache dos dados. A ideia é que o Entity vai consultar uma vez a lista de cidades e guardar esta lista em memória do servidor. Ai toda vez que você precisar consultar esta lista, ele já pega direto da memória do que ficar consultando o banco novamente. Com isso você ocupa a sua memória com apenas as 100 cidades e todos os 500 usuário vão consumir a mesma informação. E se ocorrer alguma alteração na tabela das cidades, o próprio Entity vai se virar para atualizar o cache também. Aqui tem um link de como habilitar o cache no seu projeto.

Obs.: Agora vi que o Lucas postou uma solução melhor para isso. Use a solução abaixo somente se quiser fazer um cache para objetos fora do Entity Framework.

Olá, Jacqueline!

Acho que você pode usar um cache em memória para isso:

using System.Runtime.Caching;  

public class CacheEmMemoria: ICacheEmMemoria
{
    public T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class
    {
        T item = MemoryCache.Default.Get(cacheKey) as T;
        if (item == null)
        {
            item = getItemCallback();
            MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(10));
        }
        return item;
    }
}

interface ICacheEmMemoria
{
    T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class;
}

Como você pode usar esse serviço? Utilize o método:

cacheEmMemoria.GetOrSet("chave-do-cache", (delegate Metodo_a_chamar_se_o_cache_esta_vazio));

Note que na primeira vez, o método Metodo_a_chamar_se_o_cache_esta_vazio será invocado para preencher o cache "chave-do-cache". A partir daí, o serviço de cache irá utilizar o cache que já foi armazenado. Observe também que o cache expira em 10 minutos, então se quiser que o cache se mantenha por duas horas, você pode substituir DateTime.Now.AddMinutes(10) por DateTime.Now.AddHour(2).

Exemplo:

var cidades = cacheEmMemoria.GetOrSet("cidades", () => cidadeDAO.ListaParaDropDown())

Boa sorte e bons estudos!