我正在尝试使用F#,因此决定使用F#作为新项目的服务层。现在我正在尝试将实体映射到F#类型,但我无处可去!问题似乎是Select
条款。
在下面的示例中,IDataContext是一个实体框架工作单元,与人DbSet
(在C#
项目中定义)
interface IDataContext
{
DbSet<Person> Persons { get; }
}
方法一
[<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
这里似乎发生的问题是linq抱怨需要无参数构造函数。所以我尝试了另一种方式
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
现在我得到了
could not convert the following f# quotation to a linq expression tree
我是否必须将fun
转换为表达式?我以为F# 3.0
已经这样做了?
在最后一个例子中,我刚试过Select(fun p -> new Person())
并且它有效。那么初始化属性的方式很糟糕? C#
的相应fun p -> new Person(Id = p.Id, Name = p.Name)
会是什么?
答案 0 :(得分:1)
如果你想使用LINQ和异步查询,你需要一个解决方法,因为LINQ select不支持记录,你需要使用async 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's not null
if obj.ReferenceEquals(person, null)
then return None
else return Some ({ Id = person .Id; Name = person .Name })
} |> Async.StartAsTask
值得注意的是,LINQ和查询表达式可以返回null,您必须在某个时刻处理空值。我更喜欢尽快将它们翻译成选项。此外,我正在使用Async.StartAsTask
将Async对象转换为热门任务。
为了限制退货实体的规模,我认为这样可行(我现在没有时间对此进行全面测试):
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's not null
if obj.ReferenceEquals(person, null)
then return None
else return person |> (fun (id, name) -> Some ({ Id = id; Name = name }))
} |> Async.StartAsTask
答案 1 :(得分:0)
您是否尝试使用属性而不是字段来定义Person
:
type Person() =
member val Id = Unchecked.defaultof<int> with get, set
member val Name = Unchecked.defaultof<String> with get, set
您可以使用F#查询表达式查询EF,如下所示:
let person =
query {
for p in context.Persons do
where (p.Id = personId)
select p }
|> Seq.head
(你可能不得不使用上述方法来实现它,但这应该是它的主旨。)