2011-12-19 106 views
3

不知道这是甚至可能的,但我会解释。NHibernate嵌套投影

我有一个自定义的投影,用于在单个投影中完美工作的查询中执行简单的算术运算。

namespace Custom.Projections 
{ 
    using System.Collections.Generic; 
    using System.Text; 
    using global::NHibernate; 
    using global::NHibernate.Criterion; 
    using global::NHibernate.SqlCommand; 
    using global::NHibernate.Type; 

    /// <summary> 
    /// Represents a CalculatedProjection 
    /// </summary> 
    public class CalculatedProjection : SimpleProjection 
    { 
     private readonly CalculationType calculationType; 
     private readonly IProjection firstProjection; 
     private readonly IProjection secondProjection; 
     private readonly string firstPropertyName; 
     private readonly string secondPropertyName; 

     /// <summary> 
     /// Initializes a new instance of the CalculatedProjection class 
     /// </summary> 
     /// <param name="type">The type of calculation</param> 
     /// <param name="firstPropertyName">The name of the first property</param> 
     /// <param name="secondPropertyName">The name of the second property</param> 
     protected internal CalculatedProjection(CalculationType type, string firstPropertyName, string secondPropertyName) 
     { 
      this.calculationType = type; 
      this.firstPropertyName = firstPropertyName; 
      this.secondPropertyName = secondPropertyName; 
      System.Diagnostics.Debugger.Launch(); 
     } 

     /// <summary> 
     /// Initializes a new instance of the CalculatedProjection class 
     /// </summary> 
     /// <param name="type">The type of calculation</param> 
     /// <param name="firstProjection">The first projection</param> 
     /// <param name="secondProjection">The second projection</param> 
     protected internal CalculatedProjection(CalculationType type, IProjection firstProjection, IProjection secondProjection) 
     { 
      this.calculationType = type; 
      this.firstProjection = firstProjection; 
      this.secondProjection = secondProjection; 
     } 

     /// <summary> 
     /// The type of calculation 
     /// </summary> 
     public enum CalculationType 
     { 
      /// <summary> 
      /// Addition + 
      /// </summary> 
      Addition, 

      /// <summary> 
      /// Subtraction - 
      /// </summary> 
      Subtraction, 

      /// <summary> 
      /// Division/
      /// </summary> 
      Division, 

      /// <summary> 
      /// Division * 
      /// </summary> 
      Multiplication, 
     } 

     /// <summary> 
     /// Gets a value indicating whether the projection is grouped 
     /// </summary> 
     public override bool IsGrouped 
     { 
      get { return false; } 
     } 

     /// <summary> 
     /// Gets a value indicating whether IsAggregate. 
     /// </summary> 
     public override bool IsAggregate 
     { 
      get { return false; } 
     } 

     /// <summary> 
     /// Converts the calculation into a string 
     /// </summary> 
     /// <returns>The string representation of the calculation</returns> 
     public override string ToString() 
     { 
      var firstValue = this.firstProjection != null ? this.firstProjection.ToString() : this.firstPropertyName; 
      var secondValue = this.secondProjection != null ? this.secondProjection.ToString() : this.secondPropertyName; 

      return "(" + firstValue + TypeToString(this.calculationType) + secondValue + ")"; 
     } 

     /// <summary> 
     /// Gets the types involved in the query 
     /// </summary> 
     /// <param name="criteria">The current criteria</param> 
     /// <param name="criteriaQuery">The criteria query</param> 
     /// <returns>An array of IType</returns> 
     public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery) 
     { 
      var types = new List<IType>(); 

      if (this.firstProjection != null) 
      { 
       types.AddRange(this.firstProjection.GetTypes(criteria, criteriaQuery)); 
      } 
      else 
      { 
       types.Add(criteriaQuery.GetType(criteria, this.firstPropertyName)); 
      } 

      if (this.secondProjection != null) 
      { 
       types.AddRange(this.secondProjection.GetTypes(criteria, criteriaQuery)); 
      } 
      else 
      { 
       types.Add(criteriaQuery.GetType(criteria, this.secondPropertyName)); 
      } 

      return types.ToArray(); 
     } 

     /// <summary> 
     /// Converts the objects to an sql string representation 
     /// </summary> 
     /// <param name="criteria">The criteria being used in the query</param> 
     /// <param name="loc">The location in the query</param> 
     /// <param name="criteriaQuery">The criteria query</param> 
     /// <param name="enabledFilters">List of enabled filters</param> 
     /// <returns>The calculation as an sql string</returns> 
     public override SqlString ToSqlString(ICriteria criteria, int loc, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters) 
     { 
      string first, second; 

      if ((this.firstProjection != null) && (this.secondProjection != null)) 
      { 
       first = global::NHibernate.Util.StringHelper.RemoveAsAliasesFromSql(this.firstProjection.ToSqlString(criteria, loc, criteriaQuery, enabledFilters)).ToString(); 
       second = global::NHibernate.Util.StringHelper.RemoveAsAliasesFromSql(this.secondProjection.ToSqlString(criteria, loc, criteriaQuery, enabledFilters)).ToString(); 
      } 
      else 
      { 
       first = criteriaQuery.GetColumn(criteria, this.firstPropertyName); 
       second = criteriaQuery.GetColumn(criteria, this.secondPropertyName); 
      } 

      return new SqlString(new object[] { "(", first, TypeToString(this.calculationType), second, ") as y", loc.ToString(), "_" }); 
     } 

     /// <summary> 
     /// Converts the objects to an sql string representation 
     /// </summary> 
     /// <param name="criteria">The criteria being used in the query</param> 
     /// <param name="criteriaQuery">The criteria query</param> 
     /// <param name="enabledFilters">List of enabled filters</param> 
     /// <returns>The calculation as an sql string</returns> 
     public override SqlString ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters) 
     { 
      var sb = new StringBuilder(); 

      return new SqlString(new object[] { sb.ToString() }); 
     } 

     /// <summary> 
     /// Returns the string symbol of calculation type 
     /// </summary> 
     /// <param name="type">The type to use</param> 
     /// <returns>The string representation</returns> 
     private static string TypeToString(CalculationType type) 
     { 
      switch (type) 
      { 
       case CalculationType.Addition: return "+"; 
       case CalculationType.Subtraction: return "-"; 
       case CalculationType.Multiplication: return "*"; 
       case CalculationType.Division: return "/"; 
       default: return "+"; 
      } 
     } 
    } 
} 

我现在想使用如下的QueryOver语法使用此投影距离内的另一个:

public override IList<DaySummaryDetail> Execute() 
{ 
    // ReSharper disable PossibleNullReferenceException 
    var calculated = Custom.Projections.Calculated(CalculatedProjection.CalculationType.Subtraction, "Duration.EndTime", "Duration.StartTime"); 

    DaySummaryDetail detail = null; 

    return Session.QueryOver<WorkingDay>() 
     .SelectList(list => list 
     .Select(Projections.Group<WorkingDay>(x => x.Date).WithAlias(() => detail.Date)) 
     .Select(Projections.Sum(calculated)).WithAlias(() => detail.TotalMinutes)) 
     .Where(x => x.Person.Id == 1) 
     .TransformUsing(Transformers.AliasToBean<DaySummaryDetail>()) 
     .List<DaySummaryDetail>(); 

    // ReSharper restore PossibleNullReferenceException 
} 

生成的查询是正确的:

SELECT 
    this_.DATE_TIME as y0_, 
    sum((this_.END_MINS-this_.START_MINS)) as y1_ 
FROM 
    WORKINGDAY this_ 
WHERE 
    this_.PERSON_ID = @p0 
GROUP BY 
    this_.DATE_TIME; 
@p0 = 1 [Type: Int64 (0)] 

我的问题是我得到以下异常:

NHibernate.Exceptions.GenericADOException:could not执行查询 [SELECT this_DATE_TIME as y0_,sum((this_.END_MINS-this_.START_MINS))as y1_ FROM WORKINGDAY this_ WHERE this_.PERSON_ID = @ p0 GROUP BY this_DATE_TIME] Name:cp0 - Value:8977 [SQL:SELECT this_.DATE_TIME如y0_,总和((this_.END_MINS-this_.START_MINS))作为y1_ FROM WORKINGDAY THIS_ WHERE this_.PERSON_ID = @ P0 GROUP BY this_.DATE_TIME] ----> System.IndexOutOfRangeException: y2_

堆栈跟踪:

at System.Data.SqlClient.SqlDataReader.GetOrdinal(String name) 
at NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String name) 
at NHibernate.Loader.Criteria.CriteriaLoader.GetResultColumnOrRow(Object[] row, IResultTransformer customResultTransformer, IDataReader rs, ISessionImplementor session) 
at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) 
at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) 
at NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters) 
at NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters) 
at NHibernate.Loader.Criteria.CriteriaLoader.List(ISessionImplementor session) 
at NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results) 
at NHibernate.Impl.CriteriaImpl.List(IList results) 
at NHibernate.Impl.CriteriaImpl.List() 

你可以从混叠使用两个值(y0_和y1_)但不知何故它正在寻找y2_查询看到。 我认为这是因为我在这里使用了一个嵌套的投影,它无法处理或者是我已经实现或调用投影不正确?

任何帮助或替代建议将是伟大的。我知道这可以在一些使用HQL等方式来完成,但在事先

回答

1

男孩学校误差使用QueryOver

感谢特别感兴趣。

投影的GetTypes方法应返回投影结果中涉及的类型。我正在返回涉及的字段类型。

应该是这样的:

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

希望这可以节省有人一段时间

+0

不能将其标记为一个答案到明天 – dylman79 2011-12-20 08:07:03