Object Reference LINQ Com NHibernate

Passei por um problema muito simples, porém me atrasou pelo menos 1 dia de trabalho até descobrir o real problema.
O erro que estava ocorrendo era referente a uma query LINQ criada para ser executada pelo NHibernate(Versão 3.3.1), porém estava ocorrendo Object Reference no metodo TransformTuple, o stack Trace estava assim:

NHibernate.Exceptions.GenericADOException : Could not execute query[SQL: SQL not available]
  ----> System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
  ----> System.NullReferenceException : Object reference not set to an instance of an object.
   at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results)
   at NHibernate.Impl.AbstractSessionImpl.List(IQueryExpression queryExpression, QueryParameters parameters)
   at NHibernate.Impl.ExpressionQueryImpl.List()
   at NHibernate.Linq.DefaultQueryProvider.ExecuteQuery(NhLinqExpression nhLinqExpression, IQuery query, NhLinqExpression nhQuery)
   at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
   at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
   at Remotion.Linq.QueryableBase`1.GetEnumerator()
   at System.Linq.Enumerable.<TakeIterator>d__3a`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList(IEnumerable`1 source)
   at XXXXInfrastructure.Repository.Nhibernate.Repositorio.Repositorio.Pesquisar(Periodo periodo, Nullable`1 status, Paginacao paginacao, ref Int32 total) in EntidadeRepositorio.cs: line 59
   at Castle.Proxies.Invocations.IEntidadeRepositorio_Pesquisar.InvokeMethodOnTarget()
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at XXXX.Infrastructure.IOC.InterceptadorUnidadeTrabalho.Intercept(IInvocation invocation) in InterceptadorUnidadeTrabalho.cs: line 72
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.IEntidadeRepositorioProxy.Pesquisar(Periodo periodo, Nullable`1 status, Paginacao paginacao, ref Int32 total)
   at XXXXX.Domain.Service.Interfaces.EntidadeServico.Pesquisar(EntradaPesquisarRequestVM entrada, ref Int32 total) in EntidadeServico.cs: line 52
   at Castle.Proxies.Invocations.IEntidadeServico_Pesquisar.InvokeMethodOnTarget()
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at XXXX.Infrastructure.IOC.InterceptadorUnidadeTrabalho.Intercept(IInvocation invocation) in InterceptadorUnidadeTrabalho.cs: line 72
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.IEntidadeServicoProxy.Pesquisar(EntradaEntidadePesquisarRequestVM entrada, ref Int32 total)
   at XXXX.Application.Web.Api.Controllers.EntidadeController.Pesquisar(EntidadePesquisarRequestVM requetVm) in EntidadeController.cs: line 34
   at Tests.Integrated.Application.Web.Api.EntidadeTestes.Entidade_PesquisarPorStatus_DeveEfetuarPesquisaComSucesso() in EntidadeTestes.cs: line 75
--TargetInvocationException
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at NHibernate.Linq.ResultTransformer.TransformTuple(Object[] tuple, String[] aliases)
   at NHibernate.Hql.Ast.ANTLR.Loader.QueryLoader.GetResultList(IList results, IResultTransformer resultTransformer)
   at NHibernate.Hql.Ast.ANTLR.Loader.QueryLoader.List(ISessionImplementor session, QueryParameters queryParameters)
   at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.List(ISessionImplementor session, QueryParameters queryParameters)
   at NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results)
   at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results)
--NullReferenceException
   at lambda_method(Closure, Object[])

Depois de diversas pesquisas e sem encontrar uma solução na internet ou alguem que tivesse o mesmo erro que eu, tentei outras formas de resolver o problema como trocar para criteria a query, definir um result transform customizado para entender o problemas, interceptar a query para ver se ela estava sendo gerada com problema, porém sem sucesso.

O objeto que eu teria que retornar era assim:

   public class EntidadeDTO
    {
        public int Id { get; set; }
        public DateTime DataAbertura { get; set; }
        public DateTime? DataFechamento { get; set; }
        public StatusEntidade Status { get; set; }
        public int Totalizador1 { get; set; } //SubQuery
        public int Totalizador2 { get; set; } //SubQuery
        public int Totalizador3 { get; set; } //SubQuery
        public int Totalizador4 { get; set; }        //SubQuery
        public decimal ValorAproximado { get; set; }
        public decimal ValorFinal { get; set; } //SubQuery
    }

O erro ocorria pois a subquery que calcula o ValorFinal estava retornando null ao invez de 0, por isso ocorreu esse problema alterando para decimal? o erro parou de ocorrer, então uma lição aprendida sobre LINQ junto com NHibernate é, quando executar SubQueries tente sempre utilizar Nullable. O Objeto de retorno no final ficou assim.

   public class EntidadeDTO
    {
        public int Id { get; set; }
        public DateTime DataAbertura { get; set; }
        public DateTime? DataFechamento { get; set; }
        public StatusEntidade Status { get; set; }
        public int? Totalizador1 { get; set; } //SubQuery
        public int? Totalizador2 { get; set; } //SubQuery
        public int? Totalizador3 { get; set; } //SubQuery
        public int? Totalizador4 { get; set; }        //SubQuery
        public decimal ValorAproximado { get; set; }
        public decimal? ValorFinal { get; set; } //SubQuery
    }
Anúncios

Como Derrubar Conexões do PostgreeSQL(Timeout while getting a connection from pool)

Estava com o seguinte problema ocorrendo intermitente quando executava uma Function usando C# com NpgSQL: “Timeout while getting a connection from pool”, identifiquei que estava com problema para fechar as conexões ao executar a função e corrigi, porém ainda existia conexões pendentes travadas, segue comandos para executar para derrubar conexões ativas do PostgreSQL . Segue Link de referencia, eu testei nas duas versões e funcina normalmente: LINK

Até versão PostgreSQL 9.1:

SELECT pg_terminate_backend(pg_stat_activity.procpid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'Nome_Banco_Dados'
  AND procpid <> pg_backend_pid();

Após versão PostgreSQL 9.2:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'Nome_Banco_Dados'
  AND pid <> pg_backend_pid();

Outra dica importante é desabilitar o Pooling na connection string que pode causar um problema em concorrencia, mas isso depende do cenario da sua aplicação, o Pooling de conexão é para fazer um cache de conexões de banco de dados mantido para que as conexões podem ser reutilizados, quando são necessárias futuras solicitações para o banco de dados. Ligado ajuda a melhorar o desempenho de executar comandos numa base de dados, porém é necessário gerenciar isso para não travar as conexões.

XmlSerializer possui erro com Array de List

Um erro desses deve afetar poucas pessoas, mas na versão atual do .NET Framework 4.5.1 ocorre um erro de object reference ao executar o codigo a seguir:

       XmlSerializer serializaer = new XmlSerializer(typeof(List<string>[]));

Ao executar esse codigo ocorre um erro do tipo System.NullReferenceException, seguindo o Stack ocorre no metodo System.Xml.Serialization.CodeGenerator.GetVariableType. O Stack Completo do erro é assim:

 

at System.Xml.Serialization.CodeGenerator.GetVariableType(Object var)
at System.Xml.Serialization.SourceInfo.InternalLoad(Type elementType, Boolean asAddress)
at System.Xml.Serialization.XmlSerializationILGen.ILGenLoad(String source, Type type)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteMemberBegin(Member[] members)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteArray(String source, String arrayName, ArrayMapping arrayMapping, Boolean readOnly, Boolean isNullable, Int32 fixupIndex, Int32 elementIndex)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteElement(String source, String arrayName, String choiceSource, ElementAccessor element, ChoiceIdentifierAccessor choice, String checkSpecified, Boolean checkForNull, Boolean readOnly, Int32 fixupIndex, Int32 elementIndex)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteMemberElementsIf(Member[] members, Member anyElement, String elementElseString)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteMemberElements(Member[] members, String elementElseString, String elseString, Member anyElement, Member anyText)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteArray(String source, String arrayName, ArrayMapping arrayMapping, Boolean readOnly, Boolean isNullable, Int32 fixupIndex, Int32 elementIndex)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteElement(String source, String arrayName, String choiceSource, ElementAccessor element, ChoiceIdentifierAccessor choice, String checkSpecified, Boolean checkForNull, Boolean readOnly, Int32 fixupIndex, Int32 elementIndex)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteMemberElementsIf(Member[] members, Member anyElement, String elementElseString)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteMemberElements(Member[] members, String elementElseString, String elseString, Member anyElement, Member anyText)
at System.Xml.Serialization.XmlSerializationReaderILGen.GenerateTypeElement(XmlTypeMapping xmlTypeMapping)
at System.Xml.Serialization.XmlSerializationReaderILGen.GenerateElement(XmlMapping xmlMapping)
at System.Xml.Serialization.TempAssembly.GenerateRefEmitAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence)
at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location, Evidence evidence)
at System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type)
at MeuPrograma.Program.Main(String[] args) in d:\MeuPrograma\Program.cs:line 47
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

Porém encontrar o erro assim é muito simples, mas a serialização de XML como mostrada é utilizada em diversos outros lugares como WebAPI e WebServices(Asmx). No meu caso encontrei esse erro em um Asmx graças a esse link(que está em Frances) consegui identificar que um metodo estava retornar um objeto com Array de Lista e foi identificado o problema. Não é permitido utilizar array de List como parametro ou retorno de metodos ASMX pois pode ocrrer esse problema na serialização do cliente.

Para resolver esse problema a unica possibilidade é transformar este Array de List em um Objeto, ficando até mais organizado, ou se quiser deixar porcamente pode ser utilizado um List de List que o XmlSerializer vai funcionar.

Diferença entre override e new no C#

Vamos falar sobre os modificadores override e new. Quando utilizamos o override é possivel utilizarmos a tecnica de polimorfismo, como não declarar um objeto do tipo concreto apenas utilizar a abstração. Porém no caso do modificador new ele é apenas utilizado quando a variavel é especifica do tipo concreto. Para exemplificar será criado duas classes uma abstrata e uma concreta como a seguir:

 public abstract class MyBaseObject
    {
        public  abstract void MethodForOverride2();

        public virtual void MethodForOverride()
        {
            Console.WriteLine("MethodForOverride of MyBaseObject");
        }

        public void MethodForNew()
        {
            Console.WriteLine("MethodForNew of MyBaseObject");
        }


    }

    public class MyFirstConcreteObject : MyBaseObject
    {
        public override void MethodForOverride2()
        {
            Console.WriteLine("MethodForOverride2 of MyFirstConcreteObject");
        }

        public override void MethodForOverride()
        {
            Console.WriteLine("MethodForOverride of MyFirstConcreteObject");
        }
        public new void MethodForNew()
        {
            Console.WriteLine("MethodForNew of MyFirstConcreteObject");
        }
    }

Após isso faça a chamada assim em uma console application para executar os metodos:

            MyBaseObject myBaseObject = new MyFirstConcreteObject();
            MyFirstConcreteObject myConcreteObject = new MyFirstConcreteObject();

            Console.WriteLine("myBaseObject");
            myBaseObject.MethodForNew();
            myBaseObject.MethodForOverride();
            myBaseObject.MethodForOverride2();

            Console.WriteLine("");
            Console.WriteLine("myConcreteObject");
            myConcreteObject.MethodForNew();
            myConcreteObject.MethodForOverride();
            myConcreteObject.MethodForOverride2();

Executar esse codigo deve ter um retorno como na imagem. É possivel perceber que o metodo utilizando override sempre é utilizado da classe concreta, porém quando utilizado o modificador new depende do tipo de variavel que está sendo declarada.

Execucao

Todo o código deste post está no github neste link.

Definir Parametro generico por tipo(type)

Falando sobre reflection um necessidade que encontrei e vou colocar aqui é definir um parametro generico de uma classe por um Type, para isso podemos usar o metodo MakeGenericType. O conteudo é bem simples então vou apenas postar o codigo de como fazer sem muita necessidade de explicação.

            Type typeGenericList = typeof(MyClass);
            var ListWithoutType = typeof(IList<>); // this is a list generic without the generic type set
            var ListWithType = ListWithoutType.MakeGenericType(tipoEntidade); // this is a list generic with the generic parametier of MyClass IList<MyClass>

Iniciando com StructureMap

StructureMap é uma biblioteca open-source para fazer Injeção de dependência/ inversão de controle, ela é muito simples de configurar e utilizar, comparada com outras.  Simplificando bem para o que ela pode ser utilizada, ela é utilizada para criar um objeto de uma interface sem conhecer a classe concreta que será utilizada.

Para adicionar a biblioteca pode ser feita pelo Nuget com as versões mais atuais do visual studio ou pode ser feito o download da dll no próprio site da biblioteca.

Dentro da biblioteca a classe mais importante é a ObjectFactory, essa classe é utilizada para configurar qual objeto deve ser criado para qual interface, e quando for necessário retornar um objeto para uma interface ela também é utilizada.

Exemplo

Em uma solução normalmente temos projetos em contexto Web e outros locais(windows services, Console Applications entre outros) que utilizam as mesmas classes, porém é comum ocorrer o problema de dentro de uma dessas classes encontrar um comentários mais ou menos assim “Método deve ser chamado apenas por projetos Web” ou até mesmo diversas condições para que o método pegue as informações de um lugar ou de outro. Isso ocorre com diversas informações mas nesse caso utilizaremos apenas para algumas configurações exatamente para exemplificar.

Primeiro vamos definir o comportamento da nossa interface e uma classe que irá conter as configurações que desejamos buscar. Nossa interface IConfiguracao terá apenas um método chamado PegarConfiguracao que deve retornar uma classe com as configurações do ambiente, como o código abaixo demontra:

public interface IConfigurations
{
 ConfigurationsInfo PegarConfiguracao();
}

public class ConfigurationsInfo
{
 public TipoAmbiente Ambiente { get; set; }
 public string NomeUsuario { get; set; }
}

public enum TipoAmbiente
{
 Local,
 Web
}

Com a interface criada agora deve ser criado as classes concretas para essa interface, nesse caso vamos criar duas WebConfiguration e LocalConfiguration. Uma deverá retornar informações armazenadas na sessão utilizada pelo ASP.Net e a outra deverá retornar informações armazenadas em uma variável estática. A implementação das classe fica assim

public class WebConfiguration : IConfigurations
{
	public ConfigurationsInfo PegarConfiguracao()
	{
		if (HttpContext.Current.Session["NomeUsuario"] == null)
		{
			HttpContext.Current.Session["NomeUsuario"] = "Nome do usuario na Web";
		}
		return new ConfigurationsInfo()
			   {
				   Ambiente = TipoAmbiente.Web,
				   NomeUsuario = HttpContext.Current.Session["NomeUsuario"].ToString()
			   };
	}
}

public class LocalConfiguration : IConfigurations
{
	private static string nomeUsuario;
	public ConfigurationsInfo PegarConfiguracao()
	{
		if (nomeUsuario == null)
		{
			nomeUsuario = "Nome do usuario Local";
		}
		return new ConfigurationsInfo()
			   {
				   Ambiente = TipoAmbiente.Local,
				   NomeUsuario = nomeUsuario
			   };
	}
}

Até agora a unica coisa utilizada foi o básico de orientação a objetos. Agora nos vamos começar com o StructureMap, cria uma classe estática chamada Mapeador(Nome besta exatamente para fixar), essa classe será responsável por fazer a configuração de qual classe concreta deve ser criada para a interface, e também será utilizada para criar um objeto a partir do tipo da interface passada. A configuração será no método chamado Map, dentro dele será chamado o método configure o ObjectFactory, que permite passar a interface e qual o tipo concreto que deve ser criado. O outro método criado será o método Get que irá retornar o objeto a partir da interface. A classe irá ficar assim:

public static class Mapeador
{
	public static void Map()
	{
		
		if (HttpContext.Current == null)
		{
			ObjectFactory.Configure(x =>
			 x.For(typeof(IConfigurations)).Use(typeof(LocalConfiguration)));
		}
		else
		{
			ObjectFactory.Configure(x =>
			 x.For(typeof(IConfigurations)).Use(typeof(WebConfiguration)));
		}

	}

	public static T Get<T>()
	{
		return ObjectFactory.GetInstance<T>();
	}
}

Agora a melhor forma de testar é criar duas aplicações uma Local(no nosso caso será uma console) e uma Web e efetuar a criação o objeto e ver se está funcionando como deve. Primeiro crie uma aplicação console, nela é apenas necessário chamar primeiro o metodo Map da classe Mapeador e depois o Metodo Get. O codigo da aplicação console deve ficar assim:

	Mapeador.Map();
	IConfigurations configurations = Mapeador.Get<IConfigurations>();
	var config = configurations.PegarConfiguracao();
	Console.WriteLine(config.Ambiente + " - Usuario:" + config.NomeUsuario);

	Console.ReadKey();

A unica diferença entre a aplicação console e a aplicação web é o local que deve ser chamado o metodo Map, pois não é uma boa pratica sempre executar o metodo map, isso pode gerar repetição de codigo desnecessário e maior processamento no servidor. O melhor lugar para colocar a configuração é no arquivo Global.asax no metodo Application_Start que irá ser executado apenas quando o site é iniciado.

 

Todo o código deste post está no github neste link.