NHibernate QueryOver With Paging While Selecting Top 1 Of SubQuery

╄→尐↘猪︶ㄣ 提交于 2020-01-04 05:25:07

问题


I have 2 entities (These are broken down to question to be simpler):

Entity A

    public class EntityA
        {
            protected IList<EntityB> _bList = new List<EntityB>();

            virtual public int Id { get; set; }
            virtual public int ExtId { get; set; }


            public virtual void AddB(EntityB b)
            {
                if (!_bList.Contains(b)) _bList.Add(b);
                b.A = this;
                b.ExtId  = this.ExtId;
            }

            public virtual void RemoveB(EntityB b)
            {
                _bList.Remove(b);
            }

            public virtual IList<EntityB> BList
            {
                get { return _bList.ToList().AsReadOnly(); }
            }
        }

Entity A Mapping

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
      <class name="hibernate.domain.mappings.EntityA, hibernate.domain" lazy="true">
        <id name="Id">
          <generator class="native" />
        </id>
        <property type="int" name="ExtId" column="[ExtId]" />
        <bag
          name="BList"
          table="EntityB"
          cascade="all"
          lazy="true"
          inverse="true"
          access="field.camelcase-underscore"
          optimistic-lock="false"
          >
          <key column ="ExtId" property-ref="ExtId" />
          <one-to-many class="hibernate.domain.mappings.EntityB, hibernate.domain" />
        </bag>
    </hibernate-mapping>

Entity B

     public class EntityB
        {
            protected EntityA _a;

            virtual public int Id { get; set; }
            virtual public int ExtId { get; set; }
            virtual public EntityA A
            {
                get { return _a; }
                set { _a = value; }
            }
        }

Entity B Mapping

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
  <class name="hibernate.domain.mappings.EntityB, hibernate.domain" lazy="true">
    <id name="Id">
      <generator class="native" />
    </id>
    <property type="int" name="ExtId" column="[EXTID]" />
    <many-to-one
            name = "A"
      property-ref ="ExtId"
            not-null="true"
            class = "hibernate.domain.mappings.EntityA, hibernate.domain"
      access="field.camelcase-underscore"
            cascade = "save-update"
            fetch="select"
            insert = "false"
      lazy = "false"
            update = "false"
      column="ExtId"
      />
  </class>
</hibernate-mapping>

What I need to do is to use Queryover to get List of A with paging while selecting the first item of the B associated with A,

I have used following queryover,

    using (ISession session = SessionProvider.OpenSession())
                {
                    var bOver = (QueryOver<EntityB, EntityB>)session.QueryOver(() => bAlias)
                        .JoinAlias(() => bAlias.A, () => aAlias)
                        .SelectList(b => b.Select(() => bAlias.Id))
                        .Take(1);

                    var aOver = session.QueryOver(() => aAlias)
                        .SelectList(l => l.Select(() => aAlias.Id)
                        .SelectSubQuery<EntityB>(bOver));



var result = aOver.Skip(1).Take(1).List<object[]>();
            }

But the generated query is like, following

SELECT TOP (10) y0_,
                (SELECT TOP (10) this_0_.id AS y0_
                 FROM   (SELECT this_.id
                                AS y0_,
                                (SELECT TOP (1) this_0_.id
                                                AS
                                                y0_,
                                                Row_number() OVER(ORDER BY
                                                current_timestamp) AS
                                                __hibernate_sort_row
                                 FROM   entityb this_0_
                                        INNER JOIN entitya aalias1_
                                          ON
this_0_.extid = aalias1_.[EXTID])
AS y1_
FROM   entitya this_) AS QUERY
WHERE  QUERY.__hibernate_sort_row > 1
ORDER  BY QUERY.__hibernate_sort_row)  

And it's not near correct, So how can I solve this sort of situation (in the real world situation I need to select multiple first items like B with the A)


回答1:


Ok, I have managed to solved the situation with a little hack to the Nhibernate Projections (Actually adding a custom one)

[Serializable]
    public class TopRowProjection : SimpleProjection
    {
        private PropertyProjection _projection;

        public TopRowProjection(PropertyProjection projection)
        {
            _projection = projection;
        }

        public override bool IsAggregate
        {
            get { return true; }
        }

        public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery)
        {
            return _projection.GetTypes(criteria, criteriaQuery);
        }

        public override SqlString ToSqlString(ICriteria criteria, int position, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
        {
            SqlStringBuilder result = new SqlStringBuilder().Add(" top(1) ");
            result.Add(_projection.ToSqlString(criteria, position, criteriaQuery, enabledFilters));
            result.Add(" ");
            return result.ToSqlString();
        }

        public override string ToString()
        {
            return "select top(1)";
        }

        public override bool IsGrouped
        {
            get { return false; }
        }

        public override SqlString ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery,
                                                   IDictionary<string, IFilter> enabledFilters)
        {
            throw new InvalidOperationException("not a grouping projection");
        }
    }

And code is modified as follows, and all worked out fine

using (ISession session = SessionProvider.OpenSession())
            {
                var bOver = (QueryOver<EntityB, EntityB>)session.QueryOver(() => bAlias)
                    .JoinAlias(() => bAlias.A, () => aAlias)
                    .Select(new TopRowProjection(Projections.Property(() => bAlias.Id)));

                var aOver = session.QueryOver(() => aAlias)
                    .SelectList(l => l.Select(() => aAlias.Id)
                    .SelectSubQuery<EntityB>(bOver));

                var result = aOver.Skip(1).Take(1).List<object[]>();
            }


来源:https://stackoverflow.com/questions/7257585/nhibernate-queryover-with-paging-while-selecting-top-1-of-subquery

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!