2016-10-06 32 views
5

查询我有一个相对简单的F#查询表达式联接:leftOuterJoin和`.DefaultIfEmpty()`在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但对于一个header,至今尚未row匹配, result只是一个空序列,当查询结果被传递给一个自定义类型时,我得到一个错误,说明与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这一点,因为一种方式。但是,当我尝试使用这个例子作为查询模板:

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 

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

在理想情况下,输出为不匹配的行会是这样的(由下面的手产生截短的结果)

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])

+1

在您的交互式输出中,'result'不是一个空序列,而是一个元素的序列,而那个元素是'null'。 –

+0

感谢您的澄清。 – Steven

+4

'DefaultIfEmpty'是一个扩展方法,所以你需要'打开System.Linq'。 – kvb

回答

0

该文档是错误的;在C#中,没有直接等价于leftOuterJoin运算符,因此DefaultIfEmpty与普通联接一起使用,但在F#中,您不需要此操作(查询生成器会为您执行此转换 - 如果您好奇,请参见中的QueryBuilder.LeftOuterJoin )。

如果你想有一个传统左派的结果加入,则只需添加额外的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) 
    } 

注意,这会给你nullMDR_0916条目中缺少的,没有特殊MDR_0916值与null字段值,虽然如此,你可能想应用后期处理步骤,如果你需要后者。

+0

很好的回答,并且感谢你申请后处理步骤来创建'null'字段值的'MDR_0916'值的建议。我最终只选择了我需要的'MDR ...'中的那些字段,并重新编写了将它传递给自定义类型的方式。 – Steven