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

时间:2015-10-16 19:21:01

标签: nhibernate queryover

我已经在一个带有属性的类中定义了一个查询,但我正在尝试使用该属性构建一个相当复杂的查询并且遇到NHibernate告诉我它无法解析属性:DueDate。

My Query类如下所示:

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类

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; }
}

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

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

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映射。我在QueryOver Series - Part 9: Extending QueryOver to Use Custom Methods and Properties看了安德鲁的例子,但感觉很像仪式

我也用谷歌搜索解决方案,但我的谷歌foo让我失望..

连连呢?溶液

1 个答案:

答案 0 :(得分:1)

博客上的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
        )
  );
}