【问题标题】:How do you compare using .NET types in an NHibernate ICriteria query for an ICompositeUserType?您如何比较在 NHibernate ICriteria 查询中为 ICompositeUserType 使用 .NET 类型?
【发布时间】:2010-04-15 21:26:42
【问题描述】:

我回答了 StackOverflow 问题,关于如何在我的 POCO 中将旧版 CHAR 数据库日期和时间字段合并到一个 .NET DateTime 属性中 here(非常感谢Berryl!)。现在我试图让一个自定义 ICritera 查询来对抗那个非常 DateTime 属性无济于事。这是我的查询:

ICriteria criteria =
    Session.CreateCriteria<InputFileLog>()
    .Add(Expression.Gt(MembersOf<InputFileLog>.GetName(x => x.FileCreationDateTime), DateTime.Now.AddDays(-14)))
    .AddOrder(Order.Desc(Projections.Id()))
    .CreateCriteria(typeof(InputFile).Name)
        .Add(Expression.Eq(MembersOf<InputFile>.GetName(x => x.Id), inputFileName));

IList<InputFileLog> list = criteria.List<InputFileLog>();

这是它生成的查询:

SELECT this_.input_file_token as input1_9_2_,
    this_.file_creation_date as file2_9_2_,
    this_.file_creation_time as file3_9_2_,
    this_.approval_ind as approval4_9_2_,
    this_.file_id as file5_9_2_,
    this_.process_name as process6_9_2_,
    this_.process_status as process7_9_2_,
    this_.input_file_name as input8_9_2_,
    gonogo3_.input_file_token as input1_6_0_,
    gonogo3_.go_nogo_ind as go2_6_0_,
    inputfile1_.input_file_name as input1_3_1_,
    inputfile1_.src_code as src2_3_1_,
    inputfile1_.process_cat_code as process3_3_1_
FROM input_file_log this_
    left outer join go_nogo gonogo3_ on this_.input_file_token=gonogo3_.input_file_token
    inner join input_file inputfile1_ on this_.input_file_name=inputfile1_.input_file_name
WHERE this_.file_creation_date > :p0 and
    this_.file_creation_time > :p1 and
    inputfile1_.input_file_name = :p2
ORDER BY this_.input_file_token desc;
:p0 = '20100401',
:p1 = '15:15:27',
:p2 = 'LMCONV_JR'

查询正是我所期望的,实际上,除了它实际上并没有给我想要的东西(过去 2 周内的所有行),因为在数据库中它使用CHARs 进行了大于比较而不是DATEs。我不知道如何让查询将CHAR 值转换为查询中的DATE 而无需执行 CreateSQLQuery(),我想避免。有人知道怎么做吗?

更新: 我一直在考虑尝试使用Projections.SqlFunction() 或公式来完成此操作,但到目前为止无济于事。这是我使用SqlFunction() 的代码,但我收到NHibernate.QueryException : property does not map to a single column: FileCreationDateTime 错误:

DateTime twoWeeksAgo = DateTime.Now.AddDays(-14);
ICriteria criteria =
    Session.CreateCriteria<InputFileLog>()
    .Add(Restrictions.Gt(Projections.SqlFunction("to_date", NHibernateUtil.DateTime, Projections.Property(MembersOf<InputFileLog>.GetName(x => x.FileCreationDateTime))), twoWeeksAgo))
    //.Add(Expression.Gt(MembersOf<InputFileLog>.GetName(x => x.FileCreationDateTime), DateTime.Now.AddDays(-14)))
    .AddOrder(Order.Desc(Projections.Id()))
     .CreateCriteria(typeof(InputFile).Name)
        .Add(Expression.Eq(MembersOf<InputFile>.GetName(x => x.Id), inputFileName));

我确定我在这里做错了,它仍然不喜欢它,因为FileCreationDateTime 使用自定义ICompositeUserType 将.NET DateTime 属性拆分为两个Oracle SQL CHAR 列(有关详细信息,请参阅此 StackOverflow question)。

【问题讨论】:

  • 我不能接受我自己的答案是愚蠢的,因为我实际上是在 2 周后弄清楚的,甚至没有其他人尝试过答案(或评论他们的意见中缺乏明确性)。我想我会删除这篇文章,即使我认为它对于一个晦涩的 NHibernate 场景很有帮助。 (我显然是想得到这个评论 8o 的反应)。

标签: nhibernate legacy icriteria compositeusertype


【解决方案1】:

我终于明白了!这是代码(出于某种原因,StackOverflow 将第一个代码中的一些方法名称设置为 sn-p 类型的语法颜色):

    IList<InputFileLog> list = null;
    DateTime twoWeeksAgo = DateTime.Now.AddDays(-14);

    IProjection datePropProj =
        DefaultStringFileCreationDateTimeType.GetFileCreationDateToDateSQLProjection();
    IProjection timePropProj =
        DefaultStringFileCreationDateTimeType.GetFileCreationTimeToDateSQLProjection();

    IProjection dateConstProj =
        DefaultStringFileCreationDateTimeType.GetFileCreationDateToDateSQLFunction(twoWeeksAgo);
    IProjection timeConstProj =
        DefaultStringFileCreationDateTimeType.GetFileCreationTimeToDateSQLFunction(twoWeeksAgo);

    ICriteria criteria =
        Session.CreateCriteria<InputFileLog>()
        .Add(Restrictions.Or(Restrictions.GtProperty(datePropProj, dateConstProj),
            Restrictions.And(Restrictions.EqProperty(datePropProj, dateConstProj),
                Restrictions.GeProperty(timePropProj, timeConstProj))))
        .AddOrder(Order.Desc(Projections.Id()))
        .CreateCriteria(typeof(InputFile).Name)
            .Add(Expression.Eq(MembersOf<InputFile>.GetName(x => x.Id), inputFileName));

    list = criteria.List<InputFileLog>();

这是我用来创建SQLProjectionsSQLFunctions 的方法。我把它们放在我用于FileCreationDateTime 属性上的自定义类型映射的ICompositeUserType (DefaultStringFileCreationDateTime) 中。

public class DefaultStringFileCreationDateTime : ICompositeUserType
{
    .
    .
    .
    public const string DotNetDateFormat = "yyyyMMdd";

    public const string DotNetTimeFormat = "HH:mm:ss";

    public const string DbDateFormat = "YYYYMMDD";

    public const string DbTimeFormat = "HH24:MI:SS";

    private const string _nullDateRepresentationInDb = "00000000";

    public struct DatabaseFieldNames
    {
        /// <summary>
        /// File creation date column name.
        /// </summary>
        public const string FileCreationDate = "file_creation_date";

        /// <summary>
        /// File creation time column name.
        /// </summary>
        public const string FileCreationTime = "file_creation_time";
    }

    public static IProjection GetFileCreationDateToDateSQLProjection()
    {
        return ProjectionUtil.GetToDateSQLProjection(DatabaseFieldNames.FileCreationDate, DbDateFormat, NHibernateUtil.DateTime);
    }

    public static IProjection GetFileCreationTimeToDateSQLProjection()
    {
        return ProjectionUtil.GetToDateSQLProjection(DatabaseFieldNames.FileCreationTime, DbTimeFormat, NHibernateUtil.DateTime);
    }

    public static IProjection GetFileCreationDateToDateSQLFunction(DateTime dt)
    {
        return ProjectionUtil.GetToDateSQLFunction(dt, DotNetDateFormat, DbDateFormat);
    }

    public static IProjection GetFileCreationTimeToDateSQLFunction(DateTime dt)
    {
        return ProjectionUtil.GetToDateSQLFunction(dt, DotNetTimeFormat, DbTimeFormat);
    }
}

我已经将consts DatabaseFieldNames struct 用于PropertyNames 成员实现,因此我能够将这些硬编码的列名重用于我需要的Projections

这是通用to_date 方法所在的Projection 实用程序类:

public class ProjectionUtil
{
    public static IProjection GetToDateSQLProjection(
        string columnName, string dbToDateFormat, IType returnType)
    {
        return Projections.SqlProjection(
            string.Format("to_date({0}, '{1}') as {0}", columnName, dbToDateFormat),
            new string[] { columnName },
            new IType[] { returnType });
    }

    public static IProjection GetToDateSQLFunction(
        DateTime dt, string dotNetFormatString, string dbFormatString)
    {
        return Projections.SqlFunction(
            "to_date",
            NHibernateUtil.DateTime,
            Projections.Constant(dt.ToString(dotNetFormatString)),
            Projections.Constant(dbFormatString));
    }
}

最后,这是 NHibernate 生成的 Oracle SQL:

SELECT
    this_.input_file_token as input1_9_2_,
    this_.file_creation_date as file2_9_2_,
    this_.file_creation_time as file3_9_2_,
    this_.approval_ind as approval4_9_2_,
    this_.file_id as file5_9_2_,
    this_.process_name as process6_9_2_,
    this_.process_status as process7_9_2_,
    this_.input_file_name as input8_9_2_,
    gonogo3_.input_file_token as input1_6_0_,
    gonogo3_.go_nogo_ind as go2_6_0_,
    inputfile1_.input_file_name as input1_3_1_,
    inputfile1_.src_code as src2_3_1_,
    inputfile1_.process_cat_code as process3_3_1_
FROM
    input_file_log this_
    left outer join go_nogo gonogo3_ on this_.input_file_token=gonogo3_.input_file_token
    inner join input_file inputfile1_ on this_.input_file_name=inputfile1_.input_file_name
WHERE
    (
        to_date(file_creation_date, 'YYYYMMDD') > to_date(:p0, :p1) or 
        (
            to_date(file_creation_date, 'YYYYMMDD') = to_date(:p2, :p3) and
            to_date(file_creation_time, 'HH24:MI:SS') >= to_date(:p4, :p5)
        )
    ) and
    inputfile1_.input_file_name = :p6
ORDER BY this_.input_file_token desc;
:p0 = '20100415',
:p1 = 'YYYYMMDD',
:p2 = '20100415',
:p3 = 'YYYYMMDD',
:p4 = '18:48:48',
:p5 = 'HH24:MI:SS',
:p6 = 'LMCONV_JR'

不敢相信我得到了这个!我以为我肯定会求助于ISQLQuery

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多