繁体   English   中英

如何使用F#的LINQ提供程序?

[英]How to use a LINQ provider from F#?

在使用提供程序(例如LINQ to NHibernate)时在F#中使用LINQ查询的正确方法是什么,以便像在C#中一样工作(相同的AST)?

我的具体问题是将查询转换为F#会在C#工作时抛出错误。 这可能是由于F#没有生成相同的AST。 Roslyn为C#提供了Visual Studio AST可视化器扩展,但我不知道任何用于F#的AST查看器。

有以下工作C#查询:

.First(someEntity => someEntity.SomeNullableInt.HasValue);

当翻译为F#时:

.First(fun someEntity -> someEntity.SomeNullableInt.HasValue)

它失败并出现以下错误:

System.NotSupportedException: Boolean Invoke(System.Nullable`1[System.Int32])
>    at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression)
   at NHibernate.Linq.Visitors.QueryModelVisitor.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, Int32 index)
   at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel)
   at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
   at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root)
   at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory, Boolean filter)
   at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
   at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
   at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
   at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
   at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery)
   at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
   at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
   ...
Stopped due to error

使用.First(fun someEntity -> someEntity.SomeReferenceType <> null)可以正常工作,这导致上面的结论:在使用.HasValue的情况下,AST的生成方式不同。

通常没有任何方法可以从C#生成与F#相同的表达式树。 在这种特殊情况下,我认为问题是F#有时会插入值类型的防御性副本以防止可能的突变,因此生成的实际报价将相当于更像

someEntity => ((System.Func<bool?,bool>)(copyOfNullable => copyOfNullable.HasValue)).Invoke(someEntity.SomeNullableInt)

这是不幸的,因为可空类型是不可变的,因此这些防御性副本是不必要的,但是F#编译器通常不可能确定给定类型是否可变,因此在很多情况下不会严格需要防御性副本。

要解决这个问题,一个选项是定义一个帮助器方法来简化你不需要的表达式树元素,这样你就可以调用类似的东西。

.First(Simplify(fun someEntity -> someEntity.SomeNullableInt.HasValue))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM