【问题标题】:leftOuterJoin and `.DefaultIfEmpty()` queries in F#F# 中的 leftOuterJoin 和 `.DefaultIfEmpty()` 查询
【发布时间】:2016-10-08 00:43:27
【问题描述】:

我有一个相对简单的带有连接的F# 查询表达式:

let mdrQuery = 
    query {
        for header in db.CustomerDetails do
        leftOuterJoin row in db.MDR_0916
            on (header.PID = row.PID) into result
        select (result, header)
        } 

这会返回每个headerresult,但对于在row 中不匹配的headerresult 只是一个空序列,当查询结果传递给自定义类型时,我得到一个错误,即未定义与 row 中的字段关联的构造函数。这对于在row 中不匹配的任何header 是有意义的,将返回null 序列。一个例子:

mdrQuery |> Seq.head;;
val it :
  seq<dbSchema.ServiceTypes.MDR_0916> * dbSchema.ServiceTypes.CustomerDetails
= (seq [null], CustomerDetails {ACCOUNTMANAGER = null;
                            ACCOUNTSTATUS = "XC";
                            ADDRESSLINE1 = null;
                            ADDRESSLINE2 = null;
                            ADDRESSLINE3 = null;
                            ADDRESSLINE4 = "123 PIG ROAD"...

由于the leftOuterJoin documentation here,我怀疑有办法解决这个问题。但是,当我尝试将该示例用作 my 查询的模板时:

let mdrQuery = 
    query {
        for header in db.CustomerDetails do
        leftOuterJoin row in db.MDR_0916
            on (header.PID = row.PID) into result
        for row in result.DefaultIfEmpty() do
        select (result, header)
        }

.DefaultIfEmpty()

出错
error FS0039: The field, constructor or member 'DefaultIfEmpty' is not defined

有没有一种方法可以让这个连接发生选择每一行,用None(或其他一些空 SQL 空值)填充 result 中不匹配的行,以便整个查询可以传递给我的记录类型吗?

理想情况下,不匹配行的输出类似于(以下手动创建的截断结果)

mdrQuery |> Seq.head;;
val it :
  seq<dbSchema.ServiceTypes.MDR_0916> * dbSchema.ServiceTypes.CustomerDetails
= (MDR_0916 {AIMExp = null;
         AP = null;
         APComp = null;
         APEng = null;
         APFine = null;
         APForl = null;...}, 
CustomerDetails {ACCOUNTMANAGER = null;
                            ACCOUNTSTATUS = "XC";
                            ADDRESSLINE1 = null;
                            ADDRESSLINE2 = null;
                            ADDRESSLINE3 = null;
                            ADDRESSLINE4 = "123 PIG ROAD"...

编辑: This question/answer 与我的相似,但包括 ToOption result 只会输出 Some (seq [null])

【问题讨论】:

  • 在你的交互式输出中,result 不是一个空序列,而是一个元素的序列,那个元素是null
  • 感谢您的澄清。
  • DefaultIfEmpty是扩展方法,所以需要open System.Linq
  • 打开System.Linq 会清除错误,但不会影响其他任何内容。

标签: f#


【解决方案1】:

文档有误;在 C# 中没有直接等效于 leftOuterJoin 运算符,因此 DefaultIfEmpty 与普通连接一起使用,但在 F# 中您不需要它(查询生成器为您执行此转换 - 请参阅 QueryBuilder.LeftOuterJoinsource 如果你好奇的话)。

如果你想要传统左连接的结果,那么只需添加额外的for 循环没有 DefaultIfEmpty(但请注意 - 你想选择新绑定的row 值, 不是result序列):

let mdrQuery = 
    query {
        for header in db.CustomerDetails do
        leftOuterJoin row in db.MDR_0916
            on (header.PID = row.PID) into result
        for row in result do
        select (row, header)
    }

请注意,这将为您提供缺少的 MDR_0916 条目的 null 值,而不是带有 null 字段值的特殊 MDR_0916 值,因此您可能需要应用后处理步骤,如果您需要后者。

【讨论】:

  • 很好的答案,感谢您建议应用后处理步骤来创建具有null 字段值的MDR_0916 值。我最终只从MDR... 中选择了我需要的那些字段,并重写了我如何将其传递给自定义类型。
猜你喜欢
  • 1970-01-01
  • 2020-04-22
  • 2012-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-03
  • 2020-03-20
  • 1970-01-01
相关资源
最近更新 更多