带有自定义投影和查询参数的 QueryOver

QueryOver With Custom Projection and Query Parameter

我在 class 中使用 属性 定义了一个查询,但我正在尝试使用 属性 构建一个相当复杂的查询并将 运行 放入NHibernate 告诉我它无法解析 属性: DueDate.

我的查询 class 如下所示:

public class SomeQuery {
  public DateTime DueDate { get; private set; }
  public SomeQuery(DateTime dueDate) {
    DueDate = dueDate;
  }

  public QueryOver GetQueryOver() {

    PrimaryObject po = null;
    SubObject so = null;

    return QueryOver.Of<PrimaryObject>(() => po)
      .JoinAlias(() => so.SubObjects, () => so)
      .Where(
        Restrictions.Le(
          DateProjections.DateDiff("d", () so.Value, () = DueDate), 
          0
        )
      );
  }
}

我已经完全按照 Andrew Whitaker 的博客 QueryOver Series - Part 7: Using SQL Functions

中的描述实现了 DateProjections Class

PrimaryObjectSubObject 的内容对于示例来说并不重要,除了以下内容:

public class PrimaryObject {
   public virtual Guid Id { get; set; }
   public List<SubObject> Implementations { get; set; }
}

public class SubObject {
  public virtual Guid Id { get; set; }
  public virtual string Value { get; set; }
}

对于映射,您可以假设这些字段以合理的方式映射到数据库,因为我觉得这不是问题所在。

当我尝试在测试中使用此查询时,如下所示:

var testDate = new DateTime(2015, 06, 01);
IEnumerable<PrimaryObject> result = repository.FindAll(new SomeQuery(testDate));

我得到一个 NHibernate.QueryException:

NHibernate.QueryException : could not resolve property: DueDate of: PrimaryObject

很明显,我有一个未映射的 属性,这导致投影有胃灼热感。

正在寻找一个最小的仪式解决方案来映射 DueDate。 我看过 Andrew 在 QueryOver Series - Part 9: Extending QueryOver to Use Custom Methods and Properties 中的示例,但感觉像是很多仪式。

我也 google 寻求解决方案,但我的 google foo 失败了..

建议?解决方案?

博客上的 DateDiff 实现假设您希望计算数据库字段之间的差异。这不是您想要的:您想将一个数据库字段与一个常量进行比较。

您必须重构 DateProjections 方法集以允许您将常量作为参数传递:

public static class DateProjections
{
    private const string DateDiffFormat = "datediff({0}, ?1, ?2)";


     // Here's the overload you need
    public static IProjection DateDiff
                  (
                    string datepart,
                    Expression<Func<object>> startDate,
                    DateTime endDate
                  )
   {
         return DateDiff(
                           datePart,
                           Projections.Property(startDate),
                           Projections.Constant(endDate)
                        );
   }        
    // Keeping Andrew Whitaker's original signature
    public static IProjection DateDiff
                             (
                                string datepart, 
                                Expression<Func<object>> startDate,
                                Expression<Func<object>> endDate
                             )
    {
        return DateDiff(
                         datePart,
                         Projections.Property(startDate),
                         Projections.Property(endDate)
                       );
    }
    // Added a function that's shared by 
    // all of the overloads
    public static IProjection DateDiff(
             string datepart,
             IProjection startDate,
             IProjection endDate)
    {
        // Build the function template based on the date part.
        string functionTemplate = string.Format(DateDiffFormat, datepart);

        return Projections.SqlFunction(
            new SQLFunctionTemplate(NHibernateUtil.Int32, functionTemplate),
            NHibernateUtil.Int32,
            startDate,
            endDate);
    }
}

现在您可以像这样调用它了:

public QueryOver GetQueryOver() {

   PrimaryObject po = null;
   SubObject so = null;

   return QueryOver.Of<PrimaryObject>(() => po)
     .JoinAlias(() => so.SubObjects, () => so)
     .Where(
        Restrictions.Le(
          DateProjections.DateDiff("d", () => so.Value, DueDate), 
          0
        )
  );
}