【问题标题】:F# type inferrence issue with linq and possibly entity frameworklinq 和可能的实体框架的 F# 类型推断问题
【发布时间】:2011-11-22 23:12:23
【问题描述】:

只是尝试做一些像这样简单的事情:

context.Users.Any(fun currentUser -> currentUser.UserName = userName)

Context 只是一个实体框架上下文。现在,当我将鼠标悬停在“currentUser”上时,它知道它是一个用户类型。但是我得到了:

根据之前的信息查找不确定类型的对象 这个程序点。在此之前可能需要类型注释 程序点来约束对象的类型。这可能允许 查找要解决。

现在我意识到我可以做到这一点:

context.Users.Any(fun (currentUser:User) -> currentUser.UserName = userName)

但这看起来很傻,因为 c# 可以很容易地推断类型:

context.Users.Any(currentUser => currentUser.UserName = userName)

完整的方法是这样的:

let FindAndRemoveUser(userName:String, context:StoryBoardContext) =
  if context.Users.Any(fun currentUser-> currentUser.UserName = userName) then
    let foundUser = context.Users.Where(fun innerUser -> innerUser.UserName = userName).First()
    context.Users.DeleteObject(foundUser)
    context.SaveAll() |> ignore

我认为 F# 应该与 C# 一样或更好地处理类型推断是错误的吗?

【问题讨论】:

    标签: f# type-inference


    【解决方案1】:

    我认为你的方法有一个比你描述的问题更根本的问题。当您在 C# 中将 WhereAny 与 lambda 表达式一起使用时,C# 编译器会将 lambda 转换为表达式树 Expression<Func<_, _>>,因此 LINQ to Entities 可以将代码转换为 SQL 查询。

    但是,当您使用 F# lambda 函数作为参数时,它将被编译为函数(或 Func<_, _> 类型的委托)。这意味着您的代码将调用处理函数的内存版本,并且您将在内存中进行所有处理,而不是在数据库服务器上进行!

    要在 F# 2.0 中编写查询,您需要将所有代码包装在引号中并使用来自 F# PowerPackquery 函数运行它(F# 3.0 将使它变得更好,但不幸的是这只是一个测试版)。你可能需要这样的东西:

    if query <@ context.Users |> Seq.exists (fun currentUser -> 
                  currentUser.UserName = userName) @> then
         let foundUser = 
           query <@ context.Users 
                    |> Seq.filter (fun usr -> usr.UserName = userName) 
                    |> Seq.head @>
         context.Users.DeleteObject(foundUser)  
         context.SaveAll() |> ignore  
    

    (此外,我不确定您是否需要预先检查用户是否存在 - 您可以只使用 filter 查找所有用户,然后如果返回的序列包含某些内容,则删除第一个用户)

    【讨论】:

    • 很好...很高兴我问了这个问题。我一直在寻找研究电源组的理由,现在看来这是毫无疑问的。
    • @Programmin :仅在 F# 3.0 之前(希望如此)。 :-]
    【解决方案2】:

    我想context.Users 是一个seq&lt;User&gt;,所以你可以在Seq 模块上使用高阶函数。与 Linq 相比,您将受益于 F# 序列中的类型推断:

    let FindAndRemoveUser(userName:String, context:StoryBoardContext) =
      if context.Users |> Seq.exists (fun currentUser -> currentUser.UserName = userName) then
        let foundUser = context.Users |> Seq.filter (fun innerUser -> innerUser.UserName = userName) |> Seq.head
        context.Users.DeleteObject(foundUser)
        context.SaveAll() |> ignore
    

    关于 Linq 和 F# 序列here 中的类型推断有一个有趣的线程。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-17
    • 1970-01-01
    • 1970-01-01
    • 2020-12-21
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    相关资源
    最近更新 更多