Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Build a Linq expression from an F# function, to pass to C#

I am trying use the Lex.Db database in an F# project in a WinRT 8.1 app.

I am following this tutorial for C#. I've successfuly added a reference to Lex.Db to an F# project and the simple calls in the tutorial translate to f# and compile (eg. let db = new DbInstance("demo")).

The problem is this C# code:

db.Map<Contact>().Key(i => i.Id)

-- Edit --

To save others from reading further, in F# 3.0 this is almost a non-problem. See kvb's comment below. The solution is:

db.Map<Contact>().Key(fun i => i.Id)

-- /Edit ---

The Key function expects an Expression<Func<Contact,'a>> and I am unable to build this in F#.

A very similar question appears in How to pass LinQ Expressions from F# to C# code. The recommended solution is to use LeafExpressionConverter.QuotationToLambdaExpression.

I have tried this as follows:

 type Contact() =
    member val Id = 0 with get, set
    member val FirstName = "" with get, set

 let db = new DbInstance("Demo")

 let idExpr = LeafExpressionConverter.QuotationToLambdaExpression
                        <@ fun (c : Contact) -> c.Id @>

 db.Map<Contact>().Key(idExpr) |> ignore    // <- Error

This produces a compiler error on idExpr:

Type mismatch. Expecting a Expression<Func<Contact,'a>> but given a Expression<(Contact -> int)>. The type 'Func<Contact,'a>' does not match the type 'Contact -> int'.

This question: Expression<Func<T, bool>> from a F# func seems to address the problem directly, but the solution uses Microsoft.FSharp.Linq.QuotationEvaluation, which I can't find in F# 3.0 for WinRT.

How do I turn <@ fun (c : Contact) -> c.Id @> into an Expression<Func<Contact,'a>>?

like image 298
Stephen Hosking Avatar asked Apr 30 '14 11:04

Stephen Hosking


1 Answers

Microsoft.FSharp.Linq.QuotationEvaluation is in PowerPack, but as of v3.0 the functionality it provides is available in Core via LeafExpressionConverter. You can use the code in the question you linked, but change it to use LeafExpressionConverter for the translation part.

open System
open System.Linq.Expressions
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.RuntimeHelpers

let toLinq (expr : Expr<'a -> 'b>) =
  let linq = LeafExpressionConverter.QuotationToExpression expr
  let call = linq :?> MethodCallExpression
  let lambda = call.Arguments.[0] :?> LambdaExpression
  Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters) 
like image 80
Daniel Avatar answered Oct 03 '22 12:10

Daniel