Query using LINQ and Nhibernate

Asked

Viewed 809 times

1

I need help in a query you should search for:

PK_PARENT, NOME_PAI, {NOME_FILHO1, NOME_FILHO2, ..., NOME_FILHO*}

For research I have already tried to do research in some ways like:

var listaPai = (from parent in session.Query<Parent>() select parent).ToList();

var dto = listaPai.Select(parent => new DTOListaPai
{
    Codigo = parent.Codigo,
    NomePai = parent.Nome,
    // aqui eu faço uma consulta e já monto uma string com o formato  
    // desejado
    NomesFilho = string.Join(",", session.Query<Child>()
        .Where<Child>(
            child => child.Parent.Codigo == parent.Codigo)
        .ToList())

ERROR: When query validates Where<Child>(child => child.Parent.Codigo == parent.Codigo) the method GetHashCode() of the Child class is invoked and the moment it attempts to do the conversion Convert.ToInt32(this.Parent.Codigo) bursts an instance of null object exception. I think I’m missing at this point, or maybe some annotation missing in the mappings.

Details about the implementation in the database are commented on in the code below.


Example classes:

public class Parent {
    //pk_parent == Codigo
    public virtual long Codigo { get; set; }
    public virtual string NomePai { get; set; }
    public virtual List<Child> Childs { get; set; }

    public bool Equals(object obj1)
    {
        var obj2 = obj1 as Parent;

        if (ReferenceEquals(null, obj2)) return false;
        if (ReferenceEquals(this, obj2)) return true;

        return this.Codigo == obj2.Codigo;
    }

    public int GetHashCode()
    {
        return Convert.ToInt32(this.Codigo);
    }        
}

public class Child {
    // pk_child == NomeFilho && Parent.Codigo
    public virtual string NomeFilho { get; set; }
    // fk_parent == Parent.Codigo
    public virtual Parent Parent { get; set; }

    public override bool Equals(object obj1)
    {
        var obj2 = obj1 as Child;

        if (ReferenceEquals(null, obj2)) return false;
        if (ReferenceEquals(this, obj2)) return true;

        return this.NomeFilho == obj2.NomeFilho &&
               this.Parent.Codigo == obj2.Parent.Codigo;
    }

    public override int GetHashCode()
    {
        return Convert.ToInt32(this.Parent.Codigo) + NomeFilho.GetHashCode();
    }
}
  • pk_child is composed of fk_parent + filename

Mappings:

public class ParentMap : ClassMap<Parent>
{
    Table("tb_parent");
    Id(parent => parent.Codigo)
            .Not.Nullable()
            .Column("pk_parent")
            .GeneratedBy.Sequence("tb_parent_pk_parent_seq");
    Map(parent => parent.Nome).Column("nome_pai")
            .Not.Nullable();
    HasMany(parent => parent.Childs)
            .KeyColumn("fk_parent")
            .Cascade.All()
            .AsBag();
}

public class ChildMap : ClassMap<Child>
{
    Table("tb_child");
    CompositeId()
            .KeyProperty(child => child.Parent.Codigo, "fk_parent")
            .KeyProperty(child=> child.Nome, "nome_filho");

    References(child => child.Parent, "fk_parent");
}

1 answer

2

Buddy, I don’t use Fluent, just the pure Nhibernate with Mapping-by-code. What I do in this case is to reference everything correctly, creating the "bags" so that I can iterate and return all the children records of this class.

Ex.:

public partial class Pessoa
{
    public virtual long IdPessoa { get; set; } // Nossa PK

    // ...Suas propriedades aqui etc, só pra exemplificar

    // Você precisa criar a classe Apelido
    public virtual IEnumerable<Apelido> ApelidoBag { get; set; }
}

My mapping class looks like this (remember that in addition to the mapping below, you also need to create the mapping class for the Nickname class):

public partial class PessoaMap : ClassMapping<Pessoa>
{
    Schema("SEU_ESQUEMA");
    Lazy(true);

    // Nossa PK que é alimentada por uma sequence de exemplo (no Oracle)
    Id(x => x.IdPessoa, map =>
    {
        map.Column("ID_PESSOA");
        map.Generator(Generators.Sequence, g => g.Params(new
        {
            sequence = "SQ_EXEMPLO"
        }));
    });

    // ...Todos os itens do mapeamento do BD aqui etc, só pra exemplificar.

    Bag(x => x.ApelidoBag, colmap =>
    {
        colmap.Key(x => x.Column("ID_PESSOA"));
        colmap.Inverse(true);
    },
    map => { map.OneToMany(); });
}

This way I can do the SELECT using the LINQ (remember to reference System.Linq and Nhibernate.Linq) just searching the person (by ID, for example) and when I need to do a foreach in the list (bag) because automatically it will bring all the records of this "person".

Ex.:

return suaSessao
    .Query<Pessoa>
    .Where(x => x.IdPessoa == 12345)
    .SingleOrDefault()
;

On behalf of Lazy(true); from Nhibernate, you can bring at any time the children records only by calling the property Nicknames and making the proper iteration in it.

Ex.:

foreach (Apelido item in seuObjPessoa.ApelidosBag)
{
    // Faça o que tiver que fazer aqui
}

Browser other questions tagged

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