NHibernate - 在 select 内将 DateTime 转换为 String 抛出异常

NHibernate - Converting DateTime to String inside select throws exception

我正在使用 NHibernate,我有一个查询,我在其中尝试 select 日期时间并将其转换为字符串:

DateDTO dateDto = null;
CultureInfo ci = CultureInfo.CreateSpecificCulture("he-IL");

var dates = _session.QueryOver<Date>()
    .Where(x => x.Client.Id == clientId)
    .Where(x => x.IsVisible != 0)
    .SelectList(lst => lst
        .Select(x => x.Id).WithAlias(() => dateDto.Id)
        .Select(x => x.DateTime.ToString("dddd dd MMMM yyyy",ci)).WithAlias(() => dateDto.Date))
    .TransformUsing(Transformers.AliasToBean<DateDTO>())
    .List<DateDTO>();

抛出以下异常:

variable 'x' of type 'Form2.Entities.Date' referenced from scope '', but it is not defined

我做错了什么?

TL;DR:NHibernate 将 QueryOver 查询转换为 SQL。它不知道如何将以下表达式转换为 SQL:

Select(x => x.DateTime.ToString("dddd dd MMMM yyyy",ci))

这就是您收到错误的原因。您有几个选择:

  1. 对结果进行一些 post 处理以获得所需的日期格式。这是最简单的修复方法。你可以这样写:

    var dates = session.QueryOver<Date>()
        .Where(x => x.IsVisible != 0)
        .SelectList(lst => lst
            .Select(x => x.Id)
            .Select(x => x.DateTime))
            .List<object[]>()
        .Select(o => new DateDTO 
        {
            Id = (int)o[0],
            Date = ((DateTime)o[1]).ToString("dddd dd MMMM yyyy", ci) 
        });
    
  2. 编写一个自定义 SQL 函数来格式化数据库端的日期。 这需要多做一些工作,但最终结果可能看起来干净一点。此实现将取决于您的 SQL 方言。此示例使用 FORMAT 函数,在 SQL Server 2014 上可用:

    ISQLFunction formatFunction =
        new SQLFunctionTemplate(NHibernateUtil.String, "FORMAT(?1, 'dddd dd MMM yyy', 'he-IL')");
    
    DateDTO dateDto = null;
    
    session.QueryOver<Date>()
        .Where(x => x.IsVisible != 0)
        .SelectList(lst => lst
            .Select(x => x.Id).WithAlias(() => dateDto.Id)
            .Select(Projections.SqlFunction(
                formatFunction,
                NHibernateUtil.String,
                Projections.Property<Date>(x => x.DateTime))
            ).WithAlias(() => dateDto.Date))
        .TransformUsing(Transformers.AliasToBean<DateDTO>())
        .List<DateDTO>()
        .Dump();
    

    这会生成以下内容 SQL:

    SELECT
        this_.Id as y0_,
        FORMAT(this_.DateTime, 'dddd dd MMM yyy', 'he-IL') as y1_ 
    FROM
        Date this_ 
    WHERE
        not (this_.IsVisible = @p0);
    

    如果您使用的 NHibernate 方言已经支持自定义函数,您甚至可能不需要创建自定义函数。

    我有一个 blog post 关于在您的查询中使用 SQL 函数,如果您有兴趣的话。 (完全公开:这是我的个人博客)。