【问题标题】:nHibernate 3.0.0.4000 handles bools differently in queries?nHibernate 3.0.0.4000 在查询中以不同方式处理布尔值?
【发布时间】:2011-02-21 07:56:28
【问题描述】:

我刚刚将 nHibernate 从版本 3.0.0.1002 更新到 3.0.0.4000。一旦我这样做了,我的许多查询就开始失败。一个这样的查询是这样的:

var items = (from b in session.Query<InvoiceDetail>() 
                            where b.Customer == AddressedToCustomer && b.IsCreditNote == !addInvoices 
                            orderby b.DueDate , b.InvoiceNumber 
                            select b).ToList(); 

在 3.0.0.1002 中生成的 SQL:

2011-02-17 15:55:43,612 调试选择 invoicedet0_.Id 为 Id3_, invoicedet0_.InvoiceNumber 为 发票N2_3_, invoicedet0_.DocumentNumber 为 文档3_3_, invoicedet0_.DocumentDate 为 Document4_3_, invoicedet0_.DueDate 为 DueDate3_, invoicedet0_.DivisionDetails as Division6_3_, invoicedet0_.IsInvoice 作为 IsInvoice3_, invoicedet0_.IsCreditNote 为 IsCredit8_3_, invoicedet0_.OriginalAmount 为 Original9_3_, invoicedet0_.Amount as Amount3_, invoicedet0_.LRNo 为 LRNo3_, invoicedet0_.LRDate 作为 LRDate3_, invoicedet0_.DispatchedBy as Dispatc13_3_, invoicedet0_.CreditDays 作为 CreditDays3_, invoicedet0_.CustomerId 为 来自 InvoiceDetails 的 CustomerId3_ invoicedet0_ 在哪里 (((invoicedet0_.CustomerId 为空)和 (@p0 为空)或 invoicedet0_.CustomerId=@p0) 和案例 当 invoicedet0_.IsCreditNote=1 时 1 else 0 end=case when @p1=1 then 1 否则 0 结束订单 invoicedet0_.DueDate asc, invoicedet0_.InvoiceNumber asc;@p0 = 101790 [类型:Int32 (0)],@p1 = False [类型:Int32(0)]

在 3.0.0.4000 中生成的 SQL:

2011-02-17 16:22:15,275 调试选择 invoicedet0_.Id 为 Id3_, invoicedet0_.InvoiceNumber 为 发票N2_3_, invoicedet0_.DocumentNumber 为 文档3_3_, invoicedet0_.DocumentDate 为 Document4_3_, invoicedet0_.DueDate 为 DueDate3_, invoicedet0_.DivisionDetails as Division6_3_, invoicedet0_.IsInvoice 作为 IsInvoice3_, invoicedet0_.IsCreditNote 为 IsCredit8_3_, invoicedet0_.OriginalAmount 为 Original9_3_, invoicedet0_.Amount as Amount3_, invoicedet0_.LRNo 为 LRNo3_, invoicedet0_.LRDate 作为 LRDate3_, invoicedet0_.DispatchedBy as Dispatc13_3_, invoicedet0_.CreditDays 作为 CreditDays3_, invoicedet0_.CustomerId 为 来自 InvoiceDetails 的 CustomerId3_ invoicedet0_ 在哪里 invoicedet0_.CustomerId=@p0 和案例 当 invoicedet0_.IsCreditNote=1 时 'true' 否则 'false' end=case when @p1='true' 然后是 'true' 否则 'false' 按 invoicedet0_.DueDate asc 结束订单, invoicedet0_.InvoiceNumber asc;@p0 = 101790 [类型:Int32 (0)],@p1 = 'False' [类型:字符串(0)]

我使用约定将布尔值转换为整数(true=1,false=0)。以前的版本正在做这种转换,新版本不是。 bool 在较新的版本中被转换为字符串,但应该按照约定转换为 int。

来自生成的 SQL:
"!addInvoices" 在 sql 查询中作为字符串传递,在以前的版本中作为 int 传递:
3.0.0.1002:@p1 = True [类型:Int32 (0)]
3.0.0.4000:@p1 = 'True' [类型:字符串 (0)]

此外,IsCreditNote 数据库字段在新版本中与“true”和“false”进行比较,在旧版本中与 1 和 0 进行比较。

其次,即使我删除了约定,这也是 3.0.0.4000 中两个不同命令的输出:
插入:

2011-02-20 10:18:22,977 调试插入 INTO InvoiceDetails (InvoiceNumber, DocumentNumber、DocumentDate、DueDate、 DivisionDetails, IsInvoice, IsCreditNote, OriginalAmount, 金额, LRNo, LRDate, DispatchedBy, CreditDays, CustomerId) 值 (@p0, @p1、@p2、@p3、@p4、@p5、@p6、@p7、 @p8、@p9、@p10、@p11、@p12、@p13); 选择 last_insert_rowid();@p0 = 9070183358 [类型:Int64 (0)],@p1 = 28592879 [类型:Int64 (0)],@p2 = '20110210' [类型:字符串 (0)],@p3 = '20110303' [类型:字符串 (0)],@p4 = NULL [类型:字符串 (0)],@p5 = True [类型:布尔 (0)],@p6 = False [类型:布尔 (0)],@p7 = 2685 [类型: 十进制 (0)],@p8 = 2685 [类型: 十进制 (0)],@p9 = NULL [类型:字符串 (0)],@p10 = NULL [类型:字符串 (0)], @p11 = NULL [类型:字符串 (0)],@p12 = 21 [类型:Int32 (0)],@p13 = 101760 [类型:Int32(0)]

更新:

2011-02-20 10:10:13,941 调试选择 invoicedet0_.Id 为 Id3_, invoicedet0_.InvoiceNumber 为 发票N2_3_, invoicedet0_.DocumentNumber 为 文档3_3_, invoicedet0_.DocumentDate 为 Document4_3_, invoicedet0_.DueDate 为 DueDate3_, invoicedet0_.DivisionDetails as Division6_3_, invoicedet0_.IsInvoice 作为 IsInvoice3_, invoicedet0_.IsCreditNote 为 IsCredit8_3_, invoicedet0_.OriginalAmount 为 Original9_3_, invoicedet0_.Amount as Amount3_, invoicedet0_.LRNo 为 LRNo3_, invoicedet0_.LRDate 作为 LRDate3_, invoicedet0_.DispatchedBy as Dispatc13_3_, invoicedet0_.CreditDays 作为 CreditDays3_, invoicedet0_.CustomerId 为 来自 InvoiceDetails 的 CustomerId3_ invoicedet0_ 在哪里 invoicedet0_.CustomerId=@p0 和案例 当 invoicedet0_.IsCreditNote=1 时 'true' 否则 'false' end=case when @p1='true' 然后是 'true' 否则 'false' 按 invoicedet0_.DueDate asc 结束订单, invoicedet0_.InvoiceNumber asc;@p0 = 107233 [类型:Int32 (0)],@p1 = '真' [类型:字符串(0)]

在插入中,传递的参数是布尔值 (@p6),而在选择中,参数是字符串 (@p1)。

问题是,我将其发布为issue on nHibernate JIRA(实际上大部分内容是从该问题线程复制的),但 Patrick Earl 将该问题作为非问题关闭了。他说这是标准行为。

此版本之前的所有 nHibernate 版本都正常运行。只有这个行为不同。任何人都可以评论这真的是一个错误,还是 Patrick 正确,我需要在我的数据库中解决这个问题?

编辑:
我的数据库是 SQLite,我正在使用 Fluent nHibernate。

【问题讨论】:

  • 不,这是一个该死的错误,“查询”/LINQ 提供程序是史诗般的失败。它做了很多非常愚蠢的事情,当 Criterion 不投射该值时,选择一个 'MAX()' 值会进行投射。在我看来,LINQ 提供程序还没有准备好生产,我一直在使用 QueryOver,因为 Query 有很多问题。
  • 添加指向 jira 问题的链接。

标签: sqlite nhibernate


【解决方案1】:

菲尔是对的。 Query/LINQ 提供程序有问题。

此 Criteria/QueryOver API 完美运行:

var items = session.QueryOver<InvoiceDetail>()
        .Where(i => i.Customer == AddressedToCustomer)
        .And(i => i.IsCreditNote != addInvoices)
        .OrderBy(i => i.DueDate).Asc
        .ThenBy(i => i.InvoiceNumber).Asc
        .List();

更令人惊讶的是,提供商的开发人员只是将问题/错误作为非问题关闭,甚至没有正确调查它们。我打算将所有Query&lt;&gt; 调用替换为QueryOver&lt;&gt; 调用,以确保确定。对于像 nHibernate 这样的项目,特别考虑到像我这样热爱 linq 的开发者,这确实是一个遗憾。

【讨论】:

  • 请求重新打开并链接到这个问题怎么样?看看他们说什么会很有趣。
  • @Yogesh:QueryOver 也会有问题(它是有限的)。 Linq 在 NH 世界中是相当新的和陌生的。使用标准 API。附言我也喜欢带有 Lambda 的 LINQ,但与 Criteria API 相比,NH 中的 LINQ 支持较差。
  • @Alex - QueryOver 是 Criteria 的包装器,如果不支持某些内容,则只需调用 .UnderlyingCriteria 并回退到旧的 Criteria API。
  • @Phill:我知道它是一个包装器,Criteria API 不是遗留的,它是 NH Core 和主 API,我想说的是 QueryOver 只包装了 5% 的 NH 查询功能没有理由使用。
  • @jgauffin:我如何请求重新开放?
【解决方案2】:

一些想法:

如果您使用的是 SQL Server,请将列类型更改为布尔值的位。

尝试查询替换:

3.5.4. Query Language Substitution

You may define new NHibernate query tokens using query.substitutions. For example:
query.substitutions true=1, false=0
would cause the tokens true and false to be translated to integer literals in the generated SQL.
query.substitutions toLowercase=LOWER
would allow you to rename the SQL LOWER function.

【讨论】:

    猜你喜欢
    • 2018-07-27
    • 2016-06-29
    • 2017-01-24
    • 2013-07-16
    • 2019-11-14
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多