F# Power Pack Linq Issue - linq

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?

Does explicitly calling
System.String.op_Equality(s1,s2)
work?

You can try the quotation as:
<#fun u -> u.FirstName.Equals("Bob")#>

Related

F# Query Expressions: cannot use "for"!

For whatever reason, I cannot use a "for" construct within a query expression. What I get is the following error. The code I just what I picked that used to work -->
"error: This control construct may only be used if the computation expression builder defines a 'For' method"
#r "System.Data.Linq.dll"
#r "FSharp.Data.TypeProviders.dll"
open FSharp.Linq
open FSharp.Data.TypeProviders
[<Literal>]
let connectionString' = #"
data source = ...;
initial catalog = NORTHWND;
Integrated Security = SSPI"
type NorthwndDb =
SqlDataConnection<connectionString', Pluralize = true>
let db' = NorthwndDb.GetDataContext()
let curstomerSortedByCountry =
query { for c in db'.Customers do
sortBy c.Country
select (c.Country, c.CompanyName) }
|> Seq.cache
I was not able to test this with your code snippet (don't have a database to test this against), but I think the kind of error you are reporting would happen if you defined a variable named query somewhere in your code snippet before the query expression. For example:
let query = "oops!"
let curstomerSortedByCountry =
query { for c in [1 .. 10] do
sortBy c
select c }
error FS0708: This control construct may only be used if the computation expression builder defines a 'For' method
The reason for this is that the identifier query in query { .. } is just a variable declared in the standard F# library that has various members including query.For. If you hide this with your own declaration, then the member will not be found.

De/Serialize basic Linq Expressions using BinarySerializer

I'm looking for a library/tool in order to be able to de/serialize Linq Expressions.
Is there some library over there?
Is already suported natively on .Net? How could I get an starter stuff code?
It is unclear what you want to serialize: the result of a Linq expression, or the expression that you can use on a sequence.
IEnumerable<MyCollectionItem> MyCollection = ...;
IEnumerable<MyItem> result = MyCollection.LinqQuery(...);
Do you want to serialize result? or do you want to serialize LinqQuery, so you can use it later on a different collection:
IEnumerable<MyItem> otherResult = OtherCollection.DeserializedLinqQuery()
The first is easy: convert result to List<MyItem> and serialize / deserizalize the list.
The second is not really possible, after all, a LinqQuery is nothing more than a (possible composite) extension function to IEnumerable
static class MyCollectionItemExtensions
{
public static IEnumerable<MyItem> MyLinqQuery(this IEnumerable<MyCollectionItem>(...)
{
...
}
}
MyLinqQuery is a function, only after you've applied it to a sequence you get an object over which you can enumerate. It's not easy serialize a function.
However if MyLinqQuery is IQueryable, your query is not a function that is applied to elements of MyCollection, but something that has an expression that are applied to elements of MyCollection. You can ask the IQueryable for its expression and serialize that one.
There are several answers about how to do this in the article on StackOverflow: Serializing and deserialize expression tress

Converting C# Expression Parsing to F#

As a newbie to F#, I routinely try to convert bits of C# over as a learning exercise. In this case, I am trying to convert the following C# expression parsing code. It's simple, the idea is to pass a lambda into this function to get the string representation of a property name, rather than using standard reflection techniques. I have omitted the other GetMemberName function as I think I can figure it out once I get some guidance on what approach to take.
public static string GetMemberName<T>(Expression<Func<T, object>> expression)
{
if (expression == null)
{
throw new ArgumentException("The expression cannot be null.");
}
return GetMemberName(expression.Body);
}
I know that F# has quotations. I also know I could use Linq Expressions in F#. I would like to try it the F# way first using quotations, but I am stumbling. Could someone give me a kickstart?
I'm not sure if an exact translation of this is possible using quotations because quotations have a different shape than C# expressions. However, here's something along the same lines:
open Microsoft.FSharp.Quotations.Patterns
let GetMemberName = function
| Call (_,methodInfo,_) -> methodInfo.Name
| PropertyGet (_,propertyInfo,_) -> propertyInfo.Name
| _ -> failwith "Not a member expression"
GetMemberName <# [].IsEmpty #>
// val it : string = "IsEmpty"

c# generic orderby

In my base-repository class
i wrote this function to make possible to retrive a sorted data collection from the DB.
T is a generic defined at Class level
public abstract class RepositoryBase<T>
where T : class
The code is this:
public IList<T> GetAll<TKey>(Expression<Func<T, bool>> whereCondition, Expression<Func<T, TKey>> sortCondition, bool sortDesc = false)
{
if (sortDesc)
return this.ObjectSet.Where(whereCondition).OrderByDescending(sortCondition).ToList<T>();
return this.ObjectSet.Where(whereCondition).OrderBy(sortCondition).ToList<T>() ;
}
My goal was to introduce a generic sort parameter so that i could call the function in this way:
repo.GetAll (model=>model.field>0, model=>model.sortableField, true)
i mean that i could specify the sorting field directly via anonymous function and so using Intellisense...
Unfortunately this function doesn't work as the last code line generate errors at compile time.
I tried also to call:
repo.GetAll<Model> (model=>model.field>0, model=>model.sortableField, true)
but this don't work.
How should i write the function to meet my goal?
i'm working with EF 5, c#, .NET 4.5
You're using ObjectSet which implements IQueryable<T>. That is extended by methods on System.Linq.Queryable, which accept Expression<Func< parameters. It is correct to use those Expression parameters, as you intend for execution to occur in the database, not locally.
A Func is an anonymous delegate, a .net method.
An Expression is a tree, which may be compiled into a Func, or may be translated into Sql or something else.
You showed us a really abstract use of the method, but not an actual use of the method, or the compiler error. I suspect the error you may be making is confusing the two type parameters.
You said:
repo.GetAll<Model> (model=>model.field>0, model=>model.sortableField, true)
But this generic parameter for this method represents the type of sortableField. If sortableField isn't a Model - this is wrong.
Instead, you should be doing something like this:
Repository<Person> myRepo = new Repository<Person>();
myRepo.GetAll<DateTime>(p => p.Friends.Count() > 3, p => p.DateOfBirth, true);
If specifying the sort type breaks your intended pattern of usage, consider hiding that key by using an IOrderer: Store multi-type OrderBy expression as a property

Linq where keyword vs. Where extension and Expression parameters

Passing in an Expression to a Linq query behaves differently depending on syntax used, and I wonder why this is the case.
Let's say I have this very generic function
private IEnumerable<Company>
GetCompanies(Expression<Func<Company, bool>> whereClause)
The following implementation works as expected
private IEnumerable<Company>
GetCompanies(Expression<Func<Company, bool>> whereClause)
{
return (from c in _ctx.Companies.Where(whereClause) select c);
}
But this next implementation does not compile
(Delegate 'System.Func' does not take 1 arguments)
private IEnumerable<Company>
GetCompanies(Expression<Func<Company, bool>> whereClause)
{
return (from c in _ctx.Companies where whereClause select c);
}
Obviously I can just use the first syntax, but I was just wondering why the compiler does not treat the where keyword the same as the Where extension?
Thanks,
Thomas
The syntax for a query expression involving a where clause is (simplifying the complete grammar)
from identifier in expression where boolean-expression select expression
whereClause is not a boolean expression. To recitify this, you have to say
from c in _ctx.Companies where whereClause.Compile()(c) select c;
Note that if whereClause were a Func<Company, bool> you could get away with
from c in _ctx.Companies where whereClause(c) select c;
Note that
from x in e where f
is translated mechanically by the compiler into
(from x in e).Where(x => f)
I say mechanically because it performs this translation without doing any semantic analysis to check validity of the method calls etc. That stage comes later after all query expressions have been translated to LINQ method-invocation expressions.
In particular,
from c in _ctx.Companies where whereClause select c
is translated to
_ctx.Companies.Where(c => whereClause).Select(c)
which is clearly nonsensical.
The reason that
from c in _ctx.Companies.Where(whereClause) select c
is legit is because IEnumerable<Company>.Where has an overload accepting a Func<Company, bool> and there is an implicit conversion from an Expression<Func<Company, bool>> to a Func<Company, bool>.
You can actually shorten the whole thing to:
private IEnumerable<Company>
GetCompanies(Expression<Func<Company, bool>> whereClause)
{
return _ctx.Companies.Where(whereClause);
}
When you use the LINQ syntax, the code in the where clause is translated into an Expression<>, which represents a code tree. When you accept Expression<Func<Customer, bool>>, you are saying that your method accepts a code tree, which is converted from C# code by the compiler.
Since you already have the code tree, you have to pass it directly to the Where() method, rather than using LINQ syntax.
The difference is that in sql-like where it expects expression that evaluates to bool. But in Where method the type of expression can be the delegate.
to force second to work you can change to whereClause.Compile()(c) or change parameter to Func<Company, bool> whereClause and whereClause(c)

Resources