Error returning list with Fluent Nhibernate

Asked

Viewed 1,107 times

3

Within the Web.API project, I created a Get() method which returns a list of objects - Ilist. This Personal Classaccess has a Log list (1:N).

When executing the Get() method, an exception occurs:

<ExceptionType>System.InvalidOperationException</ExceptionType>
<ExceptionType>NHibernate.LazyInitializationException</ExceptionType>
<ExceptionMessage>Initializing[RemyWebModel.Entidades.PessoaAcesso#1]-failed to lazily initialize a collection of role: RemyWebModel.Entidades.PessoaAcesso.Logs, no session or session was closed</ExceptionMessage>

Get method():

    [HttpGet]
    public HttpResponseMessage Getall()
    {
        IList<PessoaAcesso> pessoasAcesso;

        using (var session = NHSessionFactoryManager.GetSessionFactory().OpenSession())
        {
            pessoasAcesso = session.QueryOver<PessoaAcesso>().List();
        }

        return Request.CreateResponse(HttpStatusCode.OK, pessoasAcesso, new JsonMediaTypeFormatter());
    }

Personal Classaccess:

public class PessoaAcesso : Pessoa
{
    [DataType(DataType.Text)]
    [Display(Name = "Login de acesso")]
    [RegularExpression(@"[a-zA-Z]{5,15}", ErrorMessage = "Login deve possuir somente letras e conter entre 5 a 15 caractéres!")]
    [Required(ErrorMessage = "O login deve ser preenchido!")]
    public virtual string Login { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Senha de acesso")]
    [MinLength(5)]
    [Required(ErrorMessage = "A senha deve ser informada!")]
    public virtual string Senha { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Cofirme novamente a senha")]
    [MinLength(5)]
    [Compare("Senha", ErrorMessage = "As senhas não conferem!")]
    public virtual string ConfirmarSenha { get; set; }

    [Display(Name = "Acesso Administrador?")]
    public virtual bool Administrador { get; set; }

    [Display(Name = "Acesso liberado?")]
    public virtual bool AcessoLiberado { get; set; }

    [Display(Name = "Perfil")]
    public virtual PermissaoPerfil Perfil { get; set; }

    public virtual IList<Log> Logs { get; set; }

    public PessoaAcesso()
    {
        Logs = new List<Log>();
    }
}

Log class:

public class Log
{
    public virtual int Id { get; protected set; }

    public virtual PessoaAcesso PessoaAcesso { get; set; }

    [DataType(DataType.DateTime)]
    [Display(Name = "Data/Hora")]
    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy - hh:mm:ss}")]
    public virtual DateTime DataHora { get; set; }

    [Display(Name = "Ação")]
    public virtual LogAcao Acao { get; set; }

    [DataType(DataType.Text)]
    [Display(Name = "Descrição")]
    [Required(ErrorMessage = "Descrição precisa ser preenchida!")]
    public virtual string Descricao { get; set; }
}

Personal Mapping:

public class PessoaAcessoMap : SubclassMap<PessoaAcesso>
{
    public PessoaAcessoMap()
    {
        KeyColumn("Id_Pessoa");

        Map(x => x.Login)
            .Not.Nullable()
            .Length(MapLength.TextoCurto);

        Map(x => x.Senha)
            .Not.Nullable()
            .Length(MapLength.Texto);

        Map(x => x.Administrador)
            .Not.Nullable();

        Map(x => x.AcessoLiberado)
            .Not.Nullable();

        References(x => x.Perfil)
            .Column("Id_PermissaoPerfil");

        HasMany(x => x.Logs)
            .KeyColumn("Id_PessoaAcesso")
            .Cascade.All();
    }
}

From what I understand you couldn’t load the "Log" kids because Seth’s closed, I just don’t understand where I’m going wrong. Why this error occurs?

  • How’s your Personal class mappingAccess ?

  • @Rod put the mapping code.

  • is problem in lazyload, you can enable to always load the logs of your class, .Not.Lazyload()

  • But then always keep loading the Log is complicated. Are many records.

  • Here we do not leave mapped Hasmany, for this reason, when we need, we use John alias and return, besides giving more performance

  • The error occurs because you are trying to read Logs somewhere in your code, not necessarily in Controller. It may be in the View. Nhibernate did not return a Stack Trace?

Show 1 more comment

2 answers

0

The error occurs because json serializer is trying to access the Logs property outside the session.

  • You can manually access the property, inside the using block to force the loading of it.

Or

  • Serialize your entity within the using block. Thus any Personal Entity Graphaccess will be correctly accessed.

Log size

You were worried about the size of Log’s list, right?

  • Either you log the Nhinernate map, or

  • Create a class dto to which you map your entity. And your api delivers this dto. In the mapping to dto you ignore the Log property. You can do the mapping manually, or lean on the Automapper: https://github.com/jbogard

It is good practice to isolate your domain entities from the outside world by returning a dto that best suits the api requirement.

  • I understood, but what is unclear is: If my Personal classAccess already starts the empty log list in the constructor, wasn’t Fluent/json supposed to serialize this empty list instead of trying to retrieve the log data? Remembering that it is Lazy-load.

  • What you actually access is a Proxy object that represents the Personal instance, and it is Nhibernate that controls this Proxy. Therefore, he (Nhiber) simply ignores the original implementation of his class and inserts no value in the property marked as Lazy. And then, when you try to access this property, which is actually in Proxy, Nhiber no longer has the session to search the database.

0


The problem was in the session block:

using (var session = NHSessionFactoryManager.GetSessionFactory().OpenSession())

In case, I need to leave open the session so that the result can be delivered completely, in the case of child records - Log.

So, I removed the use of using leaving the session variable open:

public IEnumerable<PessoaAcesso> GetAll()
{
        var session = NHSessionFactoryManager.GetSessionFactory().OpenSession();

        return session
            .CreateCriteria(typeof(PessoaAcesso))
            .List<PessoaAcesso>();
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.