【问题标题】:Problems with NHibernate and DateTime mappingsNHibernate 和 DateTime 映射的问题
【发布时间】:2011-11-08 09:58:07
【问题描述】:

我在查询给定的记录时遇到问题 时间跨度。

我从中选择的列是 DATE 类型。我已经映射了这个 列作为 DateTime 属性,查询有效但速度慢。

生成的查询如下:(NHProfiler提供)

select kifkalende0_.KALENDER_MEDARBEJDER_ID as KALENDER1_119_0_,
   kifkalende1_.KALENDER_EMNE_ID        as KALENDER1_210_1_,
   kifkalende0_.OPDATERET_TIDSPUNKT     as OPDATERET2_119_0_,
   kifkalende0_.AENDRET                 as AENDRET119_0_,
   kifkalende0_.OPDATERET_AF            as OPDATERET4_119_0_,
   kifkalende0_.OPRETTET_AF             as OPRETTET5_119_0_,
   kifkalende0_.OPRETTET_TIDSPUNKT      as OPRETTET6_119_0_,
   kifkalende0_.SLETTET                 as SLETTET119_0_,
   kifkalende0_.KALENDER_EMNE_ID        as KALENDER8_119_0_,
   kifkalende0_.MEDARBEJDER_ID          as MEDARBEJ9_119_0_,
   kifkalende1_.OPDATERET_TIDSPUNKT     as OPDATERET2_210_1_,
   kifkalende1_.BESKRIVELSE             as BESKRIVE3_210_1_,
   kifkalende1_.DATO                    as DATO210_1_,
   kifkalende1_.ER_FRA_SAG              as ER5_210_1_,
   kifkalende1_.FRA_SAG_ID              as FRA6_210_1_,
   kifkalende1_.FRA_TABEL               as FRA7_210_1_,
   kifkalende1_.FRA_TID                 as FRA8_210_1_,
   kifkalende1_.OPDATERET_AF            as OPDATERET9_210_1_,
   kifkalende1_.OPRETTET_AF             as OPRETTET10_210_1_,
   kifkalende1_.OPRETTET_TIDSPUNKT      as OPRETTET11_210_1_,
   kifkalende1_.SAG_TYPE                as SAG12_210_1_,
   kifkalende1_.TIL_TID                 as TIL13_210_1_,
   kifkalende1_.YDERLIGERE_BESKRIVELSE  as YDERLIGERE14_210_1_,
   kifkalende1_.EMNE_ID                 as EMNE15_210_1_,
   kifkalende1_.PERSON_ID               as PERSON16_210_1_
from   "KIF_KALENDER_MEDARBEJDER" kifkalende0_
   left outer join "KIF_KALENDER_EMNE" kifkalende1_ on 
kifkalende0_.KALENDER_EMNE_ID = kifkalende1_.KALENDER_EMNE_ID,
   "KIF_KALENDER_EMNE" kifkalende2_
where  kifkalende0_.KALENDER_EMNE_ID = kifkalende2_.KALENDER_EMNE_ID
   and (kifkalende0_.MEDARBEJDER_ID in (7624 /* :p3 */,6226 
/* :p4 */,7382 /* :p5 */,5774 /* :p6 */, 5775 /* :p7 */,8259 
/* :p8 */,8218 /* :p9 */,9899 /* :p10 */, 6000 /* :p11 */,5779 
/* :p12 */,5780 /* :p13 */,5782 /* :p14 */, 5783 /* :p15 */,5784 
/* :p16 */,5785 /* :p17 */,5788 /* :p18 */, 5789 /* :p19 */,5790 
/* :p20 */,7341 /* :p21 */,8963 /* :p22 */, 10201 /* :p23 */,10388 
/* :p24 */))       
and kifkalende2_.DATO >= TIMESTAMP '2010-11-10 00:00:00.00' /* :p0 */
and kifkalende2_.DATO <= TIMESTAMP '2010-11-10 23:59:59.00' /* :p1 */
and (kifkalende0_.SLETTET = TIMESTAMP '1899-12-31 00:00:00.00' /* :p2 */
    or kifkalende0_.SLETTET is null);

在我们的数据库中,执行大约需要 1500 毫秒。

如果我们手动将查询更改为:

select kifkalende0_.KALENDER_MEDARBEJDER_ID as KALENDER1_119_0_,
   kifkalende1_.KALENDER_EMNE_ID        as KALENDER1_210_1_,
   kifkalende0_.OPDATERET_TIDSPUNKT     as OPDATERET2_119_0_,
   kifkalende0_.AENDRET                 as AENDRET119_0_,
   kifkalende0_.OPDATERET_AF            as OPDATERET4_119_0_,
   kifkalende0_.OPRETTET_AF             as OPRETTET5_119_0_,
   kifkalende0_.OPRETTET_TIDSPUNKT      as OPRETTET6_119_0_,
   kifkalende0_.SLETTET                 as SLETTET119_0_,
   kifkalende0_.KALENDER_EMNE_ID        as KALENDER8_119_0_,
   kifkalende0_.MEDARBEJDER_ID          as MEDARBEJ9_119_0_,
   kifkalende1_.OPDATERET_TIDSPUNKT     as OPDATERET2_210_1_,
   kifkalende1_.BESKRIVELSE             as BESKRIVE3_210_1_,
   kifkalende1_.DATO                    as DATO210_1_,
   kifkalende1_.ER_FRA_SAG              as ER5_210_1_,
   kifkalende1_.FRA_SAG_ID              as FRA6_210_1_,
   kifkalende1_.FRA_TABEL               as FRA7_210_1_,
   kifkalende1_.FRA_TID                 as FRA8_210_1_,
   kifkalende1_.OPDATERET_AF            as OPDATERET9_210_1_,
   kifkalende1_.OPRETTET_AF             as OPRETTET10_210_1_,
   kifkalende1_.OPRETTET_TIDSPUNKT      as OPRETTET11_210_1_,
   kifkalende1_.SAG_TYPE                as SAG12_210_1_,
   kifkalende1_.TIL_TID                 as TIL13_210_1_,
   kifkalende1_.YDERLIGERE_BESKRIVELSE  as YDERLIGERE14_210_1_,
   kifkalende1_.EMNE_ID                 as EMNE15_210_1_,
   kifkalende1_.PERSON_ID               as PERSON16_210_1_
from   "KIF_KALENDER_MEDARBEJDER" kifkalende0_
   left outer join "KIF_KALENDER_EMNE" kifkalende1_ on 
kifkalende0_.KALENDER_EMNE_ID = kifkalende1_.KALENDER_EMNE_ID,
   "KIF_KALENDER_EMNE" kifkalende2_
where  kifkalende0_.KALENDER_EMNE_ID = kifkalende2_.KALENDER_EMNE_ID
   and (kifkalende0_.MEDARBEJDER_ID in (7624 /* :p3 */,6226 
/* :p4 */,7382 /* :p5 */,5774 /* :p6 */, 5775 /* :p7 */,8259 
/* :p8 */,8218 /* :p9 */,9899 /* :p10 */, 6000 /* :p11 */,5779 
/* :p12 */,5780 /* :p13 */,5782 /* :p14 */, 5783 /* :p15 */,5784 
/* :p16 */,5785 /* :p17 */,5788 /* :p18 */, 5789 /* :p19 */,5790 
/* :p20 */,7341 /* :p21 */,8963 /* :p22 */, 10201 /* :p23 */,10388 
/* :p24 */))  
   and kifkalende2_.DATO>=to_date('10-11-2010 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
   and kifkalende2_.DATO<=to_date('10-11-2010 23:59:59', 'DD-MM-YYYY HH24:MI:SS')
   and (kifkalende0_.SLETTET=to_date('31-12-1899 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
   or kifkalende0_.SLETTET is null);

它在大约 50 毫秒内执行。

有什么方法可以让 NHibernate 生成 to_date 而不是 日期比较的时间戳??

我对 RegisterDateTimeTypeMappings 的工作方式有点困惑 Oracle10gDialect,但我尝试扩展它,将方法更改为

            protected override void RegisterDateTimeTypeMappings()
            {
                    RegisterColumnType(DbType.Date, "DATE");
                    //RegisterColumnType(DbType.DateTime, "TIMESTAMP(4)");
                    RegisterColumnType(DbType.DateTime, "DATE");
                    RegisterColumnType(DbType.Time, "TIMESTAMP(4)");
            }

但这并没有帮助。

我们的环境是:

  • .net (C#) 4.0
  • NHibernate 3.1.0,主要通过 Linq 使用
  • ODP.Net 11.2.2.0 针对 Oracle 11g

有人有什么建议吗?

谢谢, ./丹尼尔

【问题讨论】:

    标签: nhibernate odp.net


    【解决方案1】:

    我通过覆盖以下 NHibernate 类解决了我和你的问题。 NHProfiler 仍将显示 TIMESTAMP 值,但基础参数将是 DATE 类型 - 如果您的 oracle 列也是 DateTime,它将是可索引的。 将鼠标悬停在 NHProfiler 中的参数上以了解我的意思 - 类似于: :p0: TIMESTAMP - '2011-07-01 00:00:00.00' 日期 代替 :p0: TIMESTAMP - '2011-07-01 00:00:00.00' 时间戳。

    我还在使用 Oracle 11g、C# .Net 4、Nhibernate 3.2。

    public class OracleDataClientDriver2 : OracleDataClientDriver
    {
        protected override void InitializeParameter(IDbDataParameter dbParam, string name, SqlType sqlType)
        {
            switch (sqlType.DbType)
            {
                    //Timestamp columns not indexed by Oracle 11g date columns. - Use Date 
                case DbType.DateTime:
                    base.InitializeParameter(dbParam, name, SqlTypeFactory.Date);
                    break;
                default:
                    base.InitializeParameter(dbParam, name, sqlType);
                    break;
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      如果参数类型正确,则根本不应该进行任何转换。仅当您的时间戳为字符串类型时才需要 TIMESTAMP 或 to_date()。如果参数输入正确,它应该是这样的:

      select
             tab.COL as col
         from
             TABLE tab
         where
             tab.COL = :p0;
      :p0 = 01.01.2000 00:00:00 [Type: DateTime (0)]
      

      因此,请确保将 DateTime 对象传递给查询。

      【讨论】:

      • 在我的查询和映射中,它们是 DateTime 对象。我发布的 SQL 是 Oracle 收到的 SQL。 NHibernate 或 ODP.NET 处理 .net 和 SQL 之间的转换。
      • @Djn 检查直接来自 NHibernate 的 SQL 输出(通过 NHibernate.SQL 记录器或控制台输出)而不是 NHibernate 输出。它应该看起来像我发布的那个。
      • 确实,我的查询看起来一样,在参数名称中添加了 .net 类型。无法理解为什么这么慢,我使用 NHprofiler 来获取解析的 sql。我的情况有点像this,但我无法将一些建议与我们的环境相匹配。
      猜你喜欢
      • 2010-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-11
      • 1970-01-01
      相关资源
      最近更新 更多