连接复合键时出现InvalidOperationException

时间:2013-06-04 22:42:07

标签: c# .net sql linq

我有一个LINQ查询在调用ToList()时会在运行时抛出InvalidOperationException,并且我试图找到解决方法,如果可能的话,而不必将连接分解为单独的where子句。

下面的例子中有问题的行是3和4。 loan_id是非可空类型decimal,ti_disb_id是非可空类型short。当我将它们拆分为单独的语句时,调用ToList()时没有异常。然而,它似乎在一起更有意义,所以如果有一个解决方案,我很乐意听到它。 :)

        var baseQuery = (from a in context.ti_disbursements
                         join b in context.disbursement_schedule
                             on new {a.loan_id, a.ti_disb_id} equals
                                new {b.loan_id, b.ti_disb_id} into ab
                             from b in ab.DefaultIfEmpty()
                         join c in context.business_associates
                             on a.ba_id equals c.ba_id into ac
                             from c in ac.DefaultIfEmpty()
                         join d in context.investor_loan
                             on b.loan_id equals d.loan_id into ad
                             from d in ad.DefaultIfEmpty()
                         join e in context.loan_information
                             on d.loan_id equals e.loan_id into ae
                             from e in ae.DefaultIfEmpty()
                         join f in context.loan_balances
                             on e.loan_id equals f.loan_id into af
                             from f in af.DefaultIfEmpty()
                         join g in context.ti_information
                             on e.loan_id equals g.loan_id into ag
                             from g in ag.DefaultIfEmpty()
                         select new
                         {
                             loan_id = a.loan_id,
                             ti_disb_id = a.ti_disb_id,
                             ti_freq_id = a.ti_freq_id,
                             ti_disbursements_stop_code = a.ti_stop_code,
                             tax_account_number = a.tax_account_number,
                             ti_disb_due_dt = b.ti_disb_due_dt,
                             ti_expire_dt = b.ti_expire_dt,
                             ti_disb_amt = b.ti_disb_amt,
                             schedule_id = b.schedule_id,
                             ba_name = c.ba_name,
                             inv_bank_cd = d.inv_bank_cd,
                             inv_cd = d.inv_cd,
                             inv_group_cd = d.inv_group_cd,
                             loan_name = e.loan_name,
                             prin_bal = f.prin_bal,
                             ti_bal = f.ti_bal,
                             ti_information_stop_code = g.ti_stop_cd,
                             non_escrowed_type = a.non_escrowed_type,
                             ba_type_id = a.ba_type_id,
                             bill_received_dt = a.bill_received_dt,
                         });

异常消息:

  

InvalidOperation异常未被用户代码

处理      
    

转换为值类型'Int16'失败,因为实现值为null。结果类型的泛型参数或查询必须使用可空类型。

  

提前多多谢谢!

3 个答案:

答案 0 :(得分:1)

继续Garrison的评论,我建议你使用上下文Log属性。 打开StreamWriter,然后分配给context.Log。它将为您提供在数据库上运行的确切SQL查询,您可以运行它并查看问题所在。

答案 1 :(得分:1)

您可能希望再次查看数据库。例外情况是,其中一条短路返回为空(a.ti_disb_ida.ti_disb_id)。如有必要,您可以在查询中放置if语句或使用空合并运算符。

我认为将new {a.loan_id, a.ti_disb_id}更改为new { loan = a.loan_id, disb = a.ti_disb_id ?? 0}可以解决您的问题。空合并运算符基本上是说如果该值为null,则使用提供的默认值。为了使用它,需要赋值(我只是尝试a.ti_disb_id ?? 0但它不会编译)这就是我输入属性名称的原因。参考文档是here

答案 2 :(得分:0)

所以,长话短说,经过多次调试后我发现问题在于我使用LEFT JOIN行为而不是INNER JOIN行为。

具体来说,对DefaultIfEmpty()的调用是创建行,这些行导致schedule_id的空值,其类型为非可空短(Int16),从而导致异常。通过取出这些DefaultIfEmpty()调用,不包括坏行,问题就解决了,因为schedule_id永远不会收到空值。