2

I have a simple function that makes use of the F# power pack to convert a quotation into a linq expression. The function is:

let toLinq (exp : Expr<'a -> 'b>) =
    let linq = exp.ToLinqExpression()
    let call = linq :?> MethodCallExpression
    let lambda = call.Arguments.[0] :?> LambdaExpression
    Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters)

I use this function to create expressions that are consumed by a C# library that uses linq to sql to query a database. For example I might build an expression like:

    let test = toLinq (<@fun u -> u.FirstName = "Bob"@> : Expr<Account->bool>)

and pass it to a method like:

public IEnumerable<T> Find(Expression<Func<T, bool> predicate)
{
        var result = Table.OfType<T>();         
        result = result.Where(predicate)                                    
        var resultArray = result.ToArray();            
        return resultArray;
}

This was working as designed in verion 1.9.9.9 of the power pack. However it no longer works in the latest version of the power pack. The error I recieve is Method 'Boolean GenericEqualityIntrinsic[String](System.String, System.String)' has no supported translation to SQL.

I took a look at the changes to the power pack and it seems that the linq expression that is built using the new version makes use of GenericEqualityIntrinsic for comparing the property's value with the constant, whereas in version 1.9.9.9 it made use of String.op_Equality for comparison.

Is this a correct understanding of the issue? How do I make use of the new version of the power pack to convert quotations to linq expressions that can be consumed by a c# library that uses linq to sql?

ildjarn
  • 62,044
  • 9
  • 127
  • 211

2 Answers2

2

Does explicitly calling

System.String.op_Equality(s1,s2)

work?

Brian
  • 117,631
  • 17
  • 236
  • 300
  • Yes it does. For Example if I build the expression manually: `let ManualExpression() = let pe = Expression.Parameter( Operators.typedefof, "u") let ce = Expression.Constant("Bob", typedefof) let e = Expression.Equal(Expression.PropertyOrField(pe, "Firstname"), ce) let predicate = Expression.Lambda>(e, [|pe|]) predicate` `System.String.op_Equality` is used and there is no problem. – David Dickson Jun 22 '11 at 06:41
  • Also if I modify line 523 of Linq.fs in the power pack back to what it was in version 1.9.9.9 I similarly have no problem. However, from what I can tell this will only fix the issue for equality comparisons and I will still have an issue with > < and <>. – David Dickson Jun 22 '11 at 06:48
  • 1
    I'll try and fix this issue in put it in https://github.com/robertpi/FsLinqFixed, if you send me a patch with your initial fix, that would be appreciated. – Robert Jun 22 '11 at 07:59
  • @Robert I forked your repository and sent a pull request with changes. Cheers. – David Dickson Jun 22 '11 at 09:55
  • Finally got round to merging the changes and pushing them to nuget: http://www.nuget.org/List/Packages/FsLinqFixed – Robert Jun 28 '11 at 19:16
2

You can try the quotation as:

<@fun u -> u.FirstName.Equals("Bob")@>
Ankur
  • 33,367
  • 2
  • 46
  • 72
  • this quotation will work with the new version of the power pack and LinqToSql as described above. However a quotation `<@ fun u -> u.Username <> "sam0" @>` will not work. Yet it would have in the previous version. – David Dickson Jun 22 '11 at 10:05
  • @David Dickson - Yes, you are correct. My answer was just an alternate that you can as of now with the lastest version. For `<@ fun u -> u.Username <> "sam0" @>` you can use `<@ fun u -> u.Username.Equals("sam0").Equals(false) @>` – Ankur Jun 22 '11 at 11:03