Cause sentence expression problems

I am experimenting with F # and as such decided to use F # as a service layer for a new project. Now I am trying to map an entity to an F # type, but I am not getting anything! The problem seems to be in the proposal Select

.

In the example below, the IDataContext represents the entity structure unit for working with human DbSet

(defined in the project C#

)

interface IDataContext
{
     DbSet<Person> Persons { get; }
}

      

Method one

[<CLIMutable>]
type Person = {
    Id: int
    Name: string
}

type PersonService(context: IDataContext)
    member this.GetPerson(personId) = 
        let person = context.Persons
                            .Where(fun p -> p.Id = personId)
                            .Select(fun p -> { Id = p.Id; Name = p.Name })
                            .FirstOrDefaultAsync()
        person

      

The problem that seems to come up here is that linq is complaining that a parameterless constructor is required. So I tried another way

type public Person() =
    [<DefaultValue>] val mutable Id : int
    [<DefaultValue>] val mutable Name : string

type PersonService(context: IDataContext)
    member this.GetPerson(personId) = 
        let person = context.Persons
                            .Where(fun p -> p.Id = personId)
                            .Select(fun p -> new Person(Id = p.Id, Name = p.Name))
                            .FirstOrDefaultAsync()
        person

      

and now i get

could not convert the following f# quotation to a linq expression tree

      

Do I need to convert fun

to an expression? I thought I F# 3.0

already did it?

Edit

For the last example I just tried Select(fun p -> new Person())

it and it works. So how does this initialize properties, bad? What would match C#

of fun p -> new Person(Id = p.Id, Name = p.Name)

?

+3


source to share


2 answers


If you want to use LINQ and asynchronous queries, you need a job as LINQ selection does not support writes and you need to use an asynchronous workflow :

type PersonService(context: IDataContext)
member this.GetPerson(personId) = 
    async {
        // get the actual context object
        let! person = Async.AwaitTask  
                         (context.Persons
                                 .Where(fun p -> p.Id = personId)
                                 .FirstOrDefaultAsync()))

        // map context object, if it not null
        if obj.ReferenceEquals(person, null)
            then return None
            else return Some ({ Id = person .Id; Name = person .Name })
    } |> Async.StartAsTask

      

It's worth noting that LINQ and query expressions can return null, you need to handle nulls at some point. I prefer to translate them into parameters as soon as possible. Also, I am converting an Async object to a hot task using Async.StartAsTask

.



Edit:

To limit the size of the returned object, I think this will work (I don't have time right now to fully test this):

type PersonService(context: IDataContext) =
    member this.GetPerson(personId) = 
        async {
            // get the actual context object
            let! person = Async.AwaitTask
                           (query { for p in context.Persons do
                                    where (p.Id = personId)
                                    select (p.Id, p.Name)
                            }).FirstOrDefaultAsync()

            // map context object, if it not null
            if obj.ReferenceEquals(person, null)
                then return None
                else return person |> (fun (id, name) -> Some ({ Id = id; Name = name }))
        } |> Async.StartAsTask

      

+1


source


Have you tried defining Person

like this, with properties instead of fields:

type Person() =
    member val Id = Unchecked.defaultof<int> with get, set    
    member val Name = Unchecked.defaultof<String> with get, set

      

You can use an F # query expression to query EF, for example:



let person =
    query {
        for p in context.Persons do
        where (p.Id = personId)
        select p }
    |> Seq.head

      

(You may have to play around with the above to get it to work, but that should be the gist of it.)

0


source







All Articles