Question

I'm using Table Per Type(TPT) to do inheritance in Nhibernate v3.3.1.4000. I figured out that any SQL for SubClass relationships one-to-many are wrong.

Class:

public class Repasse : Colaboracao
{
    public virtual string Descricao { get; set; }
    public virtual Decimal ValorRepasse { get; set; }
    public virtual DateTime DataInicio { get; set; }
    public virtual DateTime DataTermino { get; set; }

    [XmlIgnore]
    public virtual Usuario UsuarioExecucao { get; set; }
    [XmlIgnore]
    public virtual Usuario UsuarioMonitoramento { get; set; }
    [XmlIgnore]
    public virtual IList<RepasseRecebido> RepassesRecebidos { get; set; }
    [XmlIgnore]
    public virtual IList<RepasseProduto> Produtos { get; set; }

    public Repasse()
    {
        RepassesRecebidos = new List<RepasseRecebido>();
        Produtos = new List<RepasseProduto>();
        UsuarioExecucao = new Usuario();
        UsuarioMonitoramento = new Usuario();
    }
}

public class RepasseRecebido : Entidade
{
    public virtual string NumNotaAtorizacao { get; set; }
    public virtual Decimal ValorTaxaCambio { get; set; }
    public virtual DateTime DataRecebimento { get; set; }
    public virtual Decimal ValorRecebido { get; set; }
    public virtual string Observacao { get; set; }

    [XmlIgnore]
    public virtual Repasse Repasse { get; set; }

    [XmlIgnore]
    public virtual List<Download> Downloads { get; set; }

    public RepasseRecebido()
    {
        Repasse = new Repasse();
        Downloads = new List<Download>();
    }
}

public class RepasseProduto : Entidade
{
    public virtual int QtdProduto { get; set; }
    public virtual DateTime DataInicio { get; set; }
    public virtual DateTime DataTermino { get; set; }
    public virtual int QtdBeneficiado { get; set; }
    public virtual PublicoBeneficiado PublicoBeneficiado { get; set; }

    [XmlIgnore]
    public virtual Produto Produto { get; set; }
    [XmlIgnore]
    public virtual Repasse Repasse { get; set; }
    [XmlIgnore]
    public virtual IList<RepasseProdutoAtividade> Atividades { get; set; }

    public RepasseProduto()
    {
        Produto = new Produto();
        Repasse = new Repasse();
        Atividades = new List<RepasseProdutoAtividade>();
    }
}

public class RepasseProdutoAtividade : Entidade
{
    public virtual DateTime DataInicio { get; set; }
    public virtual DateTime DataTermino { get; set; }
    public virtual string Descricao { get; set; }

    [XmlIgnore]
    public virtual RepasseProduto RepasseProduto { get; set; }

    public RepasseProdutoAtividade()
    {
        RepasseProduto = new RepasseProduto();
    }
}

Map:

public class RepasseMap : SubclassMap<Repasse>
{
    public RepasseMap()
    {
        Schema(ConfigInstances.ObterSchema("Sigma"));
        Table("tblRepasse");
        LazyLoad();

        KeyColumn("cmpIdRepasse");

        Map(x => x.Descricao).Column("cmpDcDescricao");
        Map(x => x.ValorRepasse).Column("cmpVlValorRepasse").Not.Nullable();
        Map(x => x.DataInicio).Column("cmpDtDataInicio").Not.Nullable();
        Map(x => x.DataTermino).Column("cmpDtDataTermino").Not.Nullable();

        References(x => x.UsuarioExecucao).Column("cmpIdUsuarioExecucao");
        References(x => x.UsuarioMonitoramento).Column("cmpIdUsuarioMonitoramento");

        HasMany(x => x.RepassesRecebidos).AsBag().LazyLoad();
        HasMany(x => x.Produtos).KeyColumn("cmpIdRepasseProduto").AsBag().LazyLoad();
    }

    public class RepasseRecebidoMap : ClassMap<RepasseRecebido>
    {
        public RepasseRecebidoMap()
        {
            Schema(ConfigInstances.ObterSchema("Sigma"));
            Table("tblRecursoRepasse");
            LazyLoad();

            Id(x => x.Id).GeneratedBy.Identity().Column("cmpIdRecursoRepasse");

            Map(x => x.NumNotaAtorizacao).Column("cmpNuAutorizacaoNota").Not.Nullable();
            Map(x => x.DataRecebimento).Column("cmpDtDataRecebimento").Not.Nullable();
            Map(x => x.ValorRecebido).Column("cmpVlValorRecebido").Not.Nullable();
            Map(x => x.ValorTaxaCambio).Column("cmpVlTaxaCambio").Not.Nullable();
            Map(x => x.Observacao).Column("cmpDcObservacao");

            References(x => x.Repasse).Column("cmpIdRepasse");

            HasManyToMany(x => x.Downloads)
               .Table("tblRecursoRepasseDownload")
               .ParentKeyColumn("cmpIdRecursoRepasse")
               .ChildKeyColumn("cmpIdDownload")
               .AsBag().LazyLoad().Cascade.SaveUpdate();
        }
    }

    public class RepasseProdutoMap : ClassMap<RepasseProduto>
    {
        public RepasseProdutoMap()
        {
            Schema(ConfigInstances.ObterSchema("Sigma"));
            Table("tblRepasseProduto");
            LazyLoad();

            Id(x => x.Id).GeneratedBy.Identity().Column("cmpIdRepasseProduto");

            Map(x => x.DataInicio).Column("cmpDtDatainicio").Not.Nullable();
            Map(x => x.DataTermino).Column("cmpDtDatatermino").Not.Nullable();
            Map(x => x.QtdProduto).Column("cmpInQuantidadeproduto").Not.Nullable();
            Map(x => x.QtdBeneficiado).Column("cmpIdQuantidadeBeneficiado").Not.Nullable();
            Map(x => x.PublicoBeneficiado).Column("cmpIdPublicoBeneficiado").CustomType(typeof(PublicoBeneficiado));

            References(x => x.Produto).Column("cmpIdProduto");
            References(x => x.Repasse).Column("cmpIdRepasse");

            HasMany(x => x.Atividades).AsBag().LazyLoad();
        }
    }

    public class RepasseProdutoAtividadeMap : ClassMap<RepasseProdutoAtividade>
    {
        public RepasseProdutoAtividadeMap()
        {
            Schema(ConfigInstances.ObterSchema("Sigma"));
            Table("tblRepasseProdutoAtividade");
            LazyLoad();

            Id(x => x.Id).GeneratedBy.Identity().Column("cmpIdRepasseProdutoAtividade");

            Map(x => x.DataInicio).Column("cmpDtInicio").Not.Nullable();
            Map(x => x.DataTermino).Column("cmpDtTermino").Not.Nullable();
            Map(x => x.Descricao).Column("cmpDcAtividade").Not.Nullable();

            References(x => x.RepasseProduto).Column("cmpIdRepasseProduto");
        }
    }
}

When I query RepasseProduto then SQL is generated with an issue, the query doesn't findout how to get the Foreign Key name for the one-to-many relationship, as you can see below:

select repasse0_.cmpIdRepasse as cmpIdCol1_5_
repasse0_1_.cmpDtDataCriacao as cmpDtDat2_5_
repasse0_1_.cmpStSituacao as cmpStSit3_5_
repasse0_1_.cmpDcCancelamento as cmpDcCan4_5_
repasse0_1_.cmpIdRecurso as cmpIdRec5_5_
repasse0_.cmpDcDescricao as cmpDcDes2_7_
repasse0_.cmpVlValorRepasse as cmpVlVal3_7_
repasse0_.cmpDtDataInicio as cmpDtDat4_7_
repasse0_.cmpDtDataTermino as cmpDtDat5_7_
repasse0_.cmpIdUsuarioExecucao as cmpIdUsu6_7_
repasse0_.cmpIdUsuarioMonitoramento as cmpIdUsu7_7_ 
    from mre_sigma_dsv.dbo.tblRepasse repasse0_ 
        inner join mre_sigma_dsv.dbo.tblColaboracao repasse0_1_ 
            on repasse0_.cmpIdRepasse=repasse0_1_.cmpIdColaboracao 
        where (select cast(count(*) as INT) 
                   from mre_sigma_dsv.dbo.tblRepasseProduto produtos1_ 
                   where repasse0_.cmpIdRepasse=produtos1_.Repasse_id)>@p0

As you can see the last inner select doesn't find out the name of the foreign key from tblRepasseProduto to tblRepasse, then uses Repasse_id that doesn't represent a valid table field.

What should I do? Am I missing something when mapping my sub-class relation?

Was it helpful?

Solution

Really not sure from where the ghost column comes, but there is other issue in the mapping above. In relations one-to-many vs many-to-one, i.e. in fluent HasMany vs References, there must be/is exactly one column representing that. So we need to use the same (one) column for that and should change the mapping this way.

The RepasseMap : SubclassMap<Repasse>:

public RepasseMap()
{   ...
    // was:
    // HasMany(x => x.RepassesRecebidos).AsBag().LazyLoad();
    // HasMany(x => x.Produtos).KeyColumn("cmpIdRepasseProduto").AsBag().LazyLoad();

    // should be
    HasMany(x => x.RepassesRecebidos)
         .KeyColumn("cmpIdRepasse").AsBag().LazyLoad();
    HasMany(x => x.Produtos)
         .KeyColumn("cmpIdRepasse").AsBag().LazyLoad();
}

The RepasseRecebidoMap : ClassMap<RepasseRecebido>:

public RepasseRecebidoMap()
{   ...
    // the same column representing this relationship in table "tblRecursoRepasse"
    References(x => x.Repasse).Column("cmpIdRepasse");

The RepasseProdutoMap : ClassMap<RepasseProduto>:

public RepasseProdutoMap()
{   ...
    // the same column representing this relationship in table "tblRepasseProduto"
    References(x => x.Repasse).Column("cmpIdRepasse");

If this does not help, could you please send the query you've used and which generated that strange relationship.

Also, in the Mapping snippet above you are nesting the mapping classes ... this is not the right/required way.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top