ebb
ebb

Reputation: 9377

F# - Reconstruct Expression Tree

Alright... this question is more or less related to one I've asked earlier today (F# - "Not a valid property expression"), which @Tomas Petricek answer perfectly - however it seems my lack of knowledge and the DLR, requires me to ask once again (been trying for quite a while to mix something up without luck at all).

I'm having this function (stolen from the example Tomas gave in the previous thread):

let hasSeq (e:Expr<'a -> seq<'b>>) =
  match e with
  | Patterns.Lambda(v, Patterns.PropertyGet(Some instance, propInfo, [])) ->
      printfn "Get property %s of %A" propInfo.Name instance
      // TODO: Use 'Expr.Lambda' & 'Expr.PropGet' to construct
      // an expression tree in the expected format
  | _ -> failwith "Not a lambda!"

How would I reconstruct the expression tree with Expr.Lambda and Expr.PropGet? - I need to make the seq<'b> to ICollection<'b> instead, so that the expression in the end is like: 'a -> ICollection<'b>

Upvotes: 0

Views: 580

Answers (2)

desco
desco

Reputation: 16782

Well, if you've already decomposed quotation, then maybe you can create required expression tree by yourself without ToLinqExpression from PowerPack?

type A = 
    member this.Values : int[] = failwith "" 

open Microsoft.FSharp.Quotations

type F<'T, 'R> = System.Func<'T, 'R>
type E = System.Linq.Expressions.Expression
type IC<'T> = System.Collections.Generic.ICollection<'T> 

let toLinqPropGet (e : Expr<'T -> #seq<'R>>) = 
    match e with
    | Patterns.Lambda(_, Patterns.PropertyGet(Some _, pi, [])) 
          when typeof<IC<'R>>.IsAssignableFrom(pi.PropertyType) ->
        let p = E.Parameter(typeof<'T>)
        let propGet = E.Property(p :> E, pi)
        E.Lambda<F<'T, IC<'R>>>(propGet, p) :> E
    | _ -> failwith "PropGet expected"

let r = toLinqPropGet <@ fun (x : A) -> x.Values @>        
printfn "%A" r    

Upvotes: 3

Tomas Petricek
Tomas Petricek

Reputation: 243051

This isn't going to work.

You want to build a quotation of type Entity -> ICollection<Something> and you have a quotation of type Entity -> seq<Something>. However, entity framework only supports simple lambda functions that get some property (e.g. x => x.SomeProperty).

If your Entity has only a property Foo of type seq<Something>, then there is no way you could build a quotation with the required structure (lambda that just gets a property) and of the required type (Entity -> ICollection<Something>), because the type of the property doesn't match!

What I suggested earlier is to change the entity to also have a property FooInternal of the right type (ICollection<Something>). Then you could build a quotation x => x.FooInternal, which would work fine with entity framework.

Perhaps you could give more details about what you're actually trying to achieve? We can try to help with technical details, but it seems that you may need to adjust your design a bit (to actually work with the ICollection type as required by EF).

Upvotes: 1

Related Questions