Implementando um tipo de Criteria

Quando é necessário fazer a extensão de uma classe e não se tem o fonte pode ser utilizado o padrão de projeto Proxy.

Um caso que pode ser utilizado é quando se está utilizando NHibernate no sistema e é necessário efetuar uma extensão das funcionalidades dele, no meu caso isso serviu para implementar um campo de Deletado em algumas tabelas e sempre que executar uma query nesta tabela não buscar o que já estiver deletado.

Para implementar um novo tipo de criteria você precisa criar uma classe herdando da interface ICriteria, porém essa interface solicita a implementação de vários métodos, ai você pensa, vou acabar tentando “reinventar a roda” para implementar todos esses métodos, porém não é necessário isso, você pode criar uma variável e “copiar” todo o comportamento da implementação que já existe e alterar os pontos que é necessário, uma implementação básica seria mais ou menos assim:


public class ExemploCriteria : ICriteria
{
private CriteriaImpl _instance;
public ExemploCriteria(System.Type persistentClass, ISessionImplementor session)
{ _instance = new CriteriaImpl(persistentClass, session); }

public ExemploCriteria(System.Type persistentClass, string alias, ISessionImplementor session)
{
_instance = new CriteriaImpl(persistentClass, alias, session);
}

public ExemploCriteria(string entityOrClassName, ISessionImplementor session)
{ _instance = new CriteriaImpl(entityOrClassName, session);}

public ExemploCriteria(string entityOrClassName, string alias, ISessionImplementor session) { _instance = new CriteriaImpl(entityOrClassName, alias, session); }
public object Clone() { return _instance.Clone(); }public ICriteria SetProjection(params IProjection[] projection) { _instance.SetProjection(projection); return this; }


public ICriteria Add(ICriterion expression) { _instance.Add(expression); return this; }
public ICriteria AddOrder(Order order)
{
_instance.AddOrder(order); return this;
}


public ICriteria SetFetchMode(string associationPath, FetchMode mode) {
_instance.SetFetchMode(associationPath, mode);
return this;
}

public ICriteria SetLockMode(LockMode lockMode) { _instance.SetLockMode(lockMode); return this;}
public ICriteria SetLockMode(string alias, LockMode lockMode)
{
_instance.SetLockMode(alias, lockMode);
return this;
}
public ICriteria CreateAlias(string associationPath, string alias)
{
_instance.CreateAlias(associationPath, alias);
return this;
}

public ICriteria CreateAlias(string associationPath, string alias, JoinType joinType)
{
_instance.CreateAlias(associationPath, alias, joinType);
return this;
}
public ICriteria CreateCriteria(string associationPath)
{
_instance.CreateCriteria(associationPath);
return this;
}

public ICriteria CreateCriteria(string associationPath, JoinType joinType)
{
_instance.CreateCriteria(associationPath, joinType);
return this;
}

public ICriteria CreateCriteria(string associationPath, string alias)
{
_instance.CreateCriteria(associationPath, alias);
return this;
}

public ICriteria CreateCriteria(string associationPath, string alias, JoinType joinType)
{
_instance.CreateCriteria(associationPath, alias, joinType);
return this;
}
public ICriteria SetResultTransformer(IResultTransformer resultTransformer)
{
_instance.SetResultTransformer(resultTransformer);
return this;
}

public ICriteria SetMaxResults(int maxResults)
{
_instance.SetMaxResults(maxResults);
return this;
}

public ICriteria SetFirstResult(int firstResult)
{
_instance.SetFirstResult(firstResult);
return this;
}

public ICriteria SetFetchSize(int fetchSize)
{
_instance.SetFetchSize(fetchSize);
return this;
}

public ICriteria SetTimeout(int timeout)
{
_instance.SetTimeout(timeout);
return this;
}


public ICriteria SetCacheable(bool cacheable)
{
_instance.SetCacheable(cacheable);
return this;
}

public ICriteria SetCacheRegion(string cacheRegion)
{
_instance.SetCacheRegion(cacheRegion);
return this;
}

public ICriteria SetComment(string comment)
{
_instance.SetComment(comment);
return this;
}

public ICriteria SetFlushMode(FlushMode flushMode)
{
_instance.SetFlushMode(flushMode);
return this;
}

public ICriteria SetCacheMode(CacheMode cacheMode)
{
_instance.SetCacheMode(cacheMode);
return this;
}

public IList List()
{
return _instance.List();
}

public object UniqueResult()
{
return _instance.UniqueResult();
}

public IEnumerable Future<T>()
{
return _instance.Future<T>;();
}

public IFutureValue<T> FutureValue<T>()
{
return _instance.FutureValue<T>();
}

public void List(IList results)
{
_instance.List(results);
}

public IList<T> List<T>()
{
return _instance.List<T>();
}

public T UniqueResult<T>()
{
return _instance.UniqueResult<T>();
}

public void ClearOrders()
{
_instance.ClearOrders();
}
public ICriteria GetCriteriaByPath(string path)
{
_instance.GetCriteriaByPath(path);
return this;
}

public ICriteria GetCriteriaByAlias(string alias)
{
_instance.GetCriteriaByAlias(alias);
return this;
}

public Type GetRootEntityTypeIfAvailable()
{
return _instance.GetRootEntityTypeIfAvailable();
}

public string Alias { get { return _instance.Alias; } }
}
Essa seria a implementação mais básica para a implementação de um tipo especifico para a criteria, a partir disso dá para imaginar varias coisas possíveis para se fazer antes de determinado método de uma criteria em seu sistema, porém é necessário muito cuidado pois dependendo da arquitetura do sistema pois o seu tipo de criteria pode ser utilizada no sistema inteiro para execução de querys, assim alterando algo em uma classe dessas você pode afetar o sistema inteiro, é como o sábio Ben Parker diz “Grandes poderes trazem grandes responsabilidades!
Eu utilizei isso para quando utilizado uma entidade que estivesse com uma determinada interface(INaoDeletarFisicamente) ele buscava apenas o que não estava deletado, em um próximo post irei mostrar como fazer essa implementação disso com NHibernate.
Anúncios

Query com Criteria em NHibernate

Ao utilizar NHibernate é possível efetuar querys de diversas formas, uma delas é utilizando Criteria para criação e execução de sua query, as querys utilizaram o cenário para execução:

public class Pedido
 {
 public int Id { get; set; }
 public DateTime DataPedido { get; set; }

public IList<ItemPedido> itens { get; set; }

}
 public class ItemPedido
 {
 public int Id { get; set; }
 public Pedido Pedido { get; set; }
 public string Produto { get; set; }
 public int Quantidade { get; set; }
 }

vamos a um exemplo de uma query simples para entender a sintaxe:

ISession sessao = ObterSessaoAtual();
ICriteria criteria = sessao.CreateCriteria(typeof(Pedido));

criteria.List<Pedido>();

//efetua a busca de todos os pedidos

Agora vamos a algumas querys com algumas informacoes a mais, segue uma ideia para entender melhor as funcionalidades da criteria com Nhibernate

SELECT
PROJECTIONS
FROM
TIPO DO OBJETO
WHERE
EXPRESSIONS OU RESTRICTIONS

Agora iremos fazer a mesma consulta de cima, mais buscando um pedido com um determinado Id e trazendo apenas a coluna Data_Pedido:

ISession sessao = ObterSessaoAtual();
ICriteria criteria = sessao.CreateCriteria(typeof (Pedido)).SetProjection(
 Projections.ProjectionList()
 .Add(Projections.Property("DataPedido"), "Data_Pedido"));

criteria = criteria.Add(Expression.Eq("Id", 5));
 criteria.List<DateTime>();

Bom Isso foi totalmente o básico para utilizar querys com criteria em Nhibernate, agora nos vamos para os últimos exemplos com querys um poucos mais complexas, a query que eu vou criar irá fazer um inner join com itensPedido e trazer apenas os nomes do produto e a data do Pedido, assim irei mostrar duas coisas, como executar inner join com Criteria e como efetuar a transformação dos resultados.

public class dtoPedidos
 {
 public string nome_produto { get; set; }
 public DateTime data_pedido { get; set; }

}

//Ped é um Alias, importante sempre utilizar
//Ped.Itens é a referencia para utilizar no Join, e ItensPedidos é o Alias
 ISession session = ObterSessaoAtual();
 ICriteria criteria = session.CreateCriteria(typeof(Pedido), "Ped")
 .CreateCriteria("Ped.Itens", "ItensPedido")
 .SetProjection(
 Projections.ProjectionList()
 .Add(Projections.Property("ItensPedido.Produto"), "nome_produto")
 .Add(Projections.Property("Ped.DataPedido"), "data_pedido"));
 //Importante garantir que os alias das colunas(nome_produto, data_pedido) sejam iguais as propriedades da classe
criteria.SetResultTransformer(Transformers.AliasToBean(typeof(dtoPedidos))).List<dtoPedidos>();