4

我正在尝试执行以下 LINQ 查询。

var tasks = session.Query<Task>()
    .Where(t => t.StartDate.DayOfYear == DateTime.UtcNow.DayOfYear)
    .ToList();

这不起作用,因为不支持 DayOfYear。但是,如果我说:

var tasks = session.Query<Task>()
    .Where(t => t.StartDate.Day == DateTime.UtcNow.Day)
    .ToList();

它工作正常。所以我决定查看 NHibernate 的源代码,看看他们是如何让它工作的。我在 MsSql2000Dialect.cs(MsSql2008Dialect 类继承)中找到了以下行:

RegisterFunction("day",
    new SQLFunctionTemplate(NHibernateUtil.Int32, "datepart(day, ?1)"));

因此,我在构造函数中使用以下行创建了自己的自定义方言(继承自 MsSql2008Dialect):

RegisterFunction("dayofyear",
    new SQLFunctionTemplate(NHibernateUtil.Int32, "datepart(dy, ?1)"));

然后在我的配置中注册了自定义方言,但我仍然收到以下错误:

NHibernate.QueryException:无法解析属性:DayOfYear

如果有人能告诉我我做错了什么,我将不胜感激。谢谢

4

2 回答 2

8

你已经完成了一半的工作。

您已经告诉 NHibernate 如何将 HQLdayofyear()方法调用转换为 SQL Server 方言,但您没有告诉如何将您的 LINQ 表达式转换为 HQL。基本上您需要扩展 LINQ 提供程序。我们开始做吧!

首先,我们需要实现一个新的IHqlGeneratorForProperty. 只需BaseHqlGeneratorForProperty以这种方式扩展:

public class DateTimeDayOfYearPropertyHqlGenerator : NHibernate.Linq.Functions.BaseHqlGeneratorForProperty
{
    public DateTimeDayOfYearPropertyHqlGenerator()
    {
        SupportedProperties = new[]
            {
                ReflectionHelper.GetProperty((DateTime x) => x.DayOfYear)
            };
    }

    public override NHibernate.Hql.Ast.HqlTreeNode BuildHql(MemberInfo member, Expression expression, NHibernate.Hql.Ast.HqlTreeBuilder treeBuilder, NHibernate.Linq.Visitors.IHqlExpressionVisitor visitor)
    {
        return treeBuilder.MethodCall("dayofyear", visitor.Visit(expression).AsExpression());
    }
}

然后我们需要在某个地方注册这个新的生成器。NHibernate 使用DefaultLinqToHqlGeneratorsRegistry. 让我们扩展这个类:

public class ExtendedLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
    public ExtendedLinqToHqlGeneratorsRegistry()
    {
        this.Merge(new DateTimeDayOfYearPropertyHqlGenerator());
    }
}

最后,我们需要告诉 NHibernate 使用扩展注册表而不是默认注册表。如果您使用 Loquacious 配置,只需执行以下操作:

config.LinqToHqlGeneratorsRegistry<ExtendedLinqToHqlGeneratorsRegistry>();

或者,如果您使用 FluentNHibernate:

...
.ExposeConfiguration(cfg =>
         cfg.SetProperty(NHibernate.Cfg.Environment.LinqToHqlGeneratorsRegistry,
         typeof(ExtendedLinqToHqlGeneratorsRegistry).AssemblyQualifiedName))

现在应该可以了!

于 2013-11-07T13:41:08.660 回答
0

你可以引入一个变量:

var dateOfYearUtc= DateTime.UtcNow.DayOfYear;
var tasks = session.Query<Task>()
.Where(t => t.StartDate.DayOfYear == dateOfYearUtc)
.ToList();
于 2013-11-07T12:15:12.063 回答