2011-11-22 59 views
2

只是做一些简单的像这样:F#类型inferrence问题与LINQ和可能的实体框架

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

如果上下文是一个实体的框架范围内。现在,当我将鼠标悬停在“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#应该处理类型inf还是比C#好?

回答

4

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

但是,当您使用F#lambda函数作为参数时,它将作为函数(或Func<_, _>类型的代理)进行编译。这意味着你的代码将调用处理函数的内存版本,并且你将在内存中执行所有的处理,而不是在数据库服务器上进行处理!要在F#2.0中编写查询,您需要将所有代码包含在引用中,并使用query函数F# PowerPack(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刚刚找到的所有用户,然后删除第一个,如果返回的序列包含的东西)

+1

不错......真的很高兴我问了这个问题。我一直想要一个理由来看看这个动力包,现在看起来毫无疑问。 –

+0

@程序员:直到F#3.0(希望)。 : - ] – ildjarn

2

我想context.Usersseq<User>,所以你可以使用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类型推断一个有趣的线索。

+2

我敢肯定,这是一个IQueryable,而不是一个IEnumerable,所以这将无法正常工作......我认为你应该使用PowerPack的引用到LINQ表达式翻译器:http:// blogs.msdn.com/b/dsyme/archive/2009/10/23/a-quick-refresh-on-query-support-in-the-f-power-pack.aspx –

+0

感谢您的信息。 – pad