Search code examples
c#nhibernatefluent-nhibernate

How select only root entity and all inner entiry with identificator loaded(with statlesssession)


My hbm configuration:

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-cascade="save-update" default-lazy="false">
  <class xmlns="urn:nhibernate-mapping-2.2" dynamic-insert="true" dynamic-update="true" optimistic-lock="version" name="LittleNHibernateProject.Model.CompanyBanan, LittleNHibernateProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="CompanyBanan">
    <cache region="CompanyBanan" usage="read-write" />
    <id name="Id" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="increment" />
    </id>
    <version generated="always" name="VersionObject" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
      <column name="VersionObject" not-null="true" default="1" />
    </version>
    <many-to-one class="LittleNHibernateProject.Model.FatherBanan, LittleNHibernateProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" foreign-key="FK_CompanyBanan_FatherBanan" name="FatherBanan">
      <column name="FatherBanan_id" />
    </many-to-one>
    <property name="Name" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Name" />
    </property>
  </class>
  <class xmlns="urn:nhibernate-mapping-2.2" dynamic-insert="true" dynamic-update="true" optimistic-lock="version" name="LittleNHibernateProject.Model.JobBanan, LittleNHibernateProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="JobBanan">
    <cache region="JobBanan" usage="read-write" />
    <id name="Id" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="increment" />
    </id>
    <version generated="always" name="VersionObject" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
      <column name="VersionObject" not-null="true" default="1" />
    </version>
    <any id-type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" meta-type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="Banan">
      <meta-value value="MotherBanan" class="LittleNHibernateProject.Model.MotherBanan, LittleNHibernateProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <meta-value value="FatherBanan" class="LittleNHibernateProject.Model.FatherBanan, LittleNHibernateProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <column name="Banan_Type" />
      <column name="Banan_Id" />
    </any>
    <property name="JobName" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="JobName" />
    </property>
  </class>
  <class xmlns="urn:nhibernate-mapping-2.2" dynamic-insert="true" dynamic-update="true" optimistic-lock="version" name="LittleNHibernateProject.Model.FatherBanan, LittleNHibernateProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="FatherBanan">
    <cache region="FatherBanan" usage="read-write" />
    <id name="Id" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="increment" />
    </id>
    <version generated="always" name="VersionObject" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
      <column name="VersionObject" not-null="true" default="1" />
    </version>
    <any id-type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" meta-type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="WifeBanan">
      <meta-value value="MotherBanan" class="LittleNHibernateProject.Model.MotherBanan, LittleNHibernateProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <meta-value value="FatherBanan" class="LittleNHibernateProject.Model.FatherBanan, LittleNHibernateProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <column name="Banan_Type" />
      <column name="Banan_Id" />
    </any>
    <property name="Name" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Name" />
    </property>
    <property name="Variety" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Variety" />
    </property>
  </class>
  <class xmlns="urn:nhibernate-mapping-2.2" dynamic-insert="true" dynamic-update="true" optimistic-lock="version" name="LittleNHibernateProject.Model.MotherBanan, LittleNHibernateProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="MotherBanan">
    <cache region="MotherBanan" usage="read-write" />
    <id name="Id" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="increment" />
    </id>
    <version generated="always" name="VersionObject" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
      <column name="VersionObject" not-null="true" default="1" />
    </version>
    <any id-type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" meta-type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="HusbandBanan">
      <meta-value value="MotherBanan" class="LittleNHibernateProject.Model.MotherBanan, LittleNHibernateProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <meta-value value="FatherBanan" class="LittleNHibernateProject.Model.FatherBanan, LittleNHibernateProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <column name="Banan_Type" />
      <column name="Banan_Id" />
    </any>
    <property name="Variety" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Variety" />
    </property>
  </class>
</hibernate-mapping>

I need to select only root entity and inner entiry with identificator loaded(and I use with statlesssession). If i want to select FatherBanan i use extension:

public static List<FatherBanan> ToOnlyRefList(this IQueryable<FatherBanan> query)
        {
            var select = query.Select(sel => new {sel.Id, sel.Name, sel.Variety, WifeId = sel.WifeBanan.Id, sel.VersionObject}).ToList();

            var result = new List<FatherBanan>();
            foreach (var item in select)
            {
                result.Add(new FatherBanan
                {
                    Id = item.Id,
                    Name = item.Name,
                    Variety = item.Variety,
                    VersionObject = item.VersionObject,
                    WifeBanan = new MotherBanan{Id = item.WifeId}
                });
            }

            return result;
        }

Select FatherBanan:

                using (var sss = factorySession.OpenSession())
                {
                    var list = sss.Query<FatherBanan>().ToOnlyRefList();
                }

And Nhibernate generates SQL from table FatherBanan, it's fine.

But if I want to select JobBanan: expression select new doesn't work, generate exception don't cast JobBanan to Banan. Ok, got around it exception with use extension:

public static List<JobBanan> ToOnlyRefList(this IQueryOver<JobBanan, JobBanan> query)
        {
            var select = query
                .Select(
                Projections.Property("Id"),
                Projections.Property("JobName"),
                Projections.Property("VersionObject"),
                Projections.SqlProjection("banan_id as banan_id", new[] { "banan_id" }, new IType[] { NHibernateUtil.Int64 }),
                Projections.SqlProjection("banan_type as banan_type", new[] { "banan_type" }, new IType[] { NHibernateUtil.String })
                ).List<object[]>();

            var result = new List<JobBanan>();
            foreach (var item in select)
            {
                Banan banan = null;

                if (item[4] as string == nameof(FatherBanan))
                {
                    banan = new FatherBanan() { Id = (long)item[3] };
                }
                else
                if (item[4] as string == nameof(MotherBanan))
                {
                    banan = new MotherBanan { Id = (long)item[3] };
                }

                result.Add(new JobBanan
                {
                    Id = (long)item[0],
                    JobName = (string)item[1],
                    VersionObject = (long)item[2],
                    Banan = banan
                });
            }

            return result;
        }

Haw me got all Banan sss.Query<Banan>.ToOnlyRefList()?


Solution

  • I find one way - Just get all nested in cycle:

    var types = new Type[]{/*all type in Any mapping Banan*/};
    var result = new List<Banan>();
    foreach(var type in types)
    {
        result.AddRange(sss.Query(type.FullName).ToOnlyRefList());
    }
    

    And if the entity(and inner Entity) is not abstract then:

    
    using (var session = factorySession.OpenSession())
                {
                    var banan = 
                        session
                            .Query<CompanyBanan>()
                            .Select( sel => new
                            {
                                sel.Id,
                                BananId = sel.FatherBanan == null ? (long?)null : sel.FatherBanan.Id,
                                sel.Name,
                                sel.VersionObject
                            })
                            .ToList()
                        ;
                }
    //and convert typle to entity extension
    

    This generates SQL:

    select
        companyban0_.Id as col_0_0_, case when fatherbana1_.Id is null then TRUE else FALSE end as col_1_0_, companyban0_.FatherBanan_id as col_2_0_, companyban0_.Name as col_3_0_, companyban0_.VersionObject as col_4_0_ 
    from CompanyBanan companyban0_
    left outer join FatherBanan fatherbana1_ on companyban0_.FatherBanan_id=fatherbana1_.Id