簡體   English   中英

將自定義函數添加到EntityFramework

[英]Add custom function to EntityFramework

我想在項目中添加一個函數,以便可以過濾數據。

我希望該函數返回2個GPS位置之間的距離(以公里為單位)。

到目前為止,我已經完成:在edmx中的ConceptualModels> Schema中添加了它:

<Function Name="DistanceBetweenTwoPositions" ReturnType="Edm.Double">
          <Parameter Name="latitude_1" Type="Edm.Double" />
          <Parameter Name="longitude_1" Type="Edm.Double" />
          <Parameter Name="latitude_2" Type="Edm.Double" />
          <Parameter Name="longitude_2" Type="Edm.Double" />
          <DefiningExpression>
            DistanceBetweenTwoPositions(latitude_1, longitude_1, latitude_2, longitude_2)
          </DefiningExpression>
        </Function>

創建了具有相同名稱的部分類,以便能夠定義該函數:

[DbFunctionAttribute("DataModel", "DistanceBetweenTwoPositions")]
    public static double DistanceBetweenTwoPositions(double latitude_1, double longitude_1, double latitude_2, double longitude_2)
    {
        var rlat1 = Math.PI * latitude_1 / 180;
        var rlat2 = Math.PI * latitude_2 / 180;
        var rlon1 = Math.PI * longitude_1 / 180;
        var rlon2 = Math.PI * longitude_2 / 180;

        var theta = longitude_1 - longitude_2;
        var rtheta = Math.PI * theta / 180;

        var dist = Math.Sin(rlat1) * Math.Sin(rlat2) + Math.Cos(rlat1) * Math.Cos(rlat2) * Math.Cos(rtheta);
        dist = Math.Acos(dist);
        dist = dist * 180 / Math.PI;
        dist = dist * 60 * 1.1515;

        dist = dist * 1.609344; // Conversion to kms
        return dist;
    }

並在我的代碼中調用它:

double latitude = 0;
double longitude = 0;
var request = (from house in db.Houses
                                select 
                                new
                                {
                                    house,
                                    DistanceFromUser = BackboneDBEntitiesLocal.DistanceBetweenTwoPositions(latitude, longitude, house.Latitude.Value), house.Longitude.Value)) 
                                })
                                .Where(u=>u.DistanceFromUser <= range)
                                .OrderBy(u=>u.DistanceFromUser)
                                ;

但它不起作用,我得到以下異常:

准備函數“ DataModel.DistanceBetweenTwoPositions”的定義時發生錯誤。 有關詳細信息,請參見內部異常。

InnerException:

System.Data.Entity.Core.EntitySqlException:'DistanceBetweenTwoPositions'無法解析為有效的類型或函數。 System.Data.Entity.Core.Core.Common.EntitySql.SemanticAnalyzer.ConvertMethodExpr(MethodExpr methodExpr,Boolean includeInlineFunctions,SemanticResolver sr)靠近簡單標識符第2行第13列,位於System.Data.Entity.Core.Common.EntitySql.SemanticAnalyzer System.Data.Entity.Core.Common.EntitySql.SemanticAnalyzer.Convert(Node astExpr,SemanticResolver sr)在System.Data.Entity.Core.Common.EntitySql.SemanticAnalyzer.ConvertValueExpressionAllowUntypedNull上的.ConvertMethodExpr(Node expr,SemanticResolver sr)在System.Data.Entity.Core.Common.EntitySql.SemanticAnalyzer.ConvertQueryStatementToDbExpression(Statement astStatement,SemanticResolver sr,List 1& functionDefs) at System.Data.Entity.Core.Common.EntitySql.SemanticAnalyzer.AnalyzeQueryCommand(Node astExpr) at System.Data.Entity.Core.Common.EntitySql.CqlQuery.<AnalyzeQueryExpressionSemantics>b__8(SemanticAnalyzer analyzer, Node astExpr) at System.Data.Entity.Core.Common.EntitySql.CqlQuery.AnalyzeSemanticsCommon[TResult](Node astExpr, Perspective perspective, ParserOptions parserOptions, IEnumerable astExpr,SemanticResolver sr 1& functionDefs) at System.Data.Entity.Core.Common.EntitySql.SemanticAnalyzer.AnalyzeQueryCommand(Node astExpr) at System.Data.Entity.Core.Common.EntitySql.CqlQuery.<AnalyzeQueryExpressionSemantics>b__8(SemanticAnalyzer analyzer, Node astExpr) at System.Data.Entity.Core.Common.EntitySql.CqlQuery.AnalyzeSemanticsCommon[TResult](Node astExpr, Perspective perspective, ParserOptions parserOptions, IEnumerable 1& functionDefs) at System.Data.Entity.Core.Common.EntitySql.SemanticAnalyzer.AnalyzeQueryCommand(Node astExpr) at System.Data.Entity.Core.Common.EntitySql.CqlQuery.<AnalyzeQueryExpressionSemantics>b__8(SemanticAnalyzer analyzer, Node astExpr) at System.Data.Entity.Core.Common.EntitySql.CqlQuery.AnalyzeSemanticsCommon[TResult](Node astExpr, Perspective perspective, ParserOptions parserOptions, IEnumerable 1參數,IEnumerable 1 variables, Func 3 analysisFunction)位於System.Data.Entity.Core.Common.EntitySql.CqlQuery.AnalyzeQueryExpressionSemantics(節點astQueryCommand,透視圖,ParserOptions System.Data.Entity.Core.Common.EntitySql.CqlQuery。<> c__DisplayClass4.b__3(Node astCommand,ParserOptions validatedParserOptions)在System.Data.Entity.Core.Common.EntitySql處的parserOptions,IEnumerable 1 parameters, IEnumerable 1個變量。 CqlQuery.CompileCommon [TResult]( 3 compilationFunction) at System.Data.Entity.Core.Common.EntitySql.CqlQuery.CompileQueryCommandLambda(String queryCommandText, Perspective perspective, ParserOptions parserOptions, IEnumerable 1參數,IEnumerable 1 variables)
at System.Data.Entity.Core.Mapping.ViewGeneration.Utils.ExternalCalls.CompileFunctionDefinition(String functionDefinition, IList
String commandText,ParserOptions parserOptions,Func 3 compilationFunction) at System.Data.Entity.Core.Common.EntitySql.CqlQuery.CompileQueryCommandLambda(String queryCommandText, Perspective perspective, ParserOptions parserOptions, IEnumerable CompilationFunction 3 compilationFunction) at System.Data.Entity.Core.Common.EntitySql.CqlQuery.CompileQueryCommandLambda(String queryCommandText, Perspective perspective, ParserOptions parserOptions, IEnumerable 1 variables)
at System.Data.Entity.Core.Mapping.ViewGeneration.Utils.ExternalCalls.CompileFunctionDefinition(String functionDefinition, IList
1 variables)
at System.Data.Entity.Core.Mapping.ViewGeneration.Utils.ExternalCalls.CompileFunctionDefinition(String functionDefinition, IList
1 variables)
at System.Data.Entity.Core.Mapping.ViewGeneration.Utils.ExternalCalls.CompileFunctionDefinition(String functionDefinition, IList
EdmFunction function) 1 variables)
at System.Data.Entity.Core.Mapping.ViewGeneration.Utils.ExternalCalls.CompileFunctionDefinition(String functionDefinition, IList
1 functionParameters,EdmItemCollection edmItemCollection)在System.Data.Entity.Core.Metadata.Edm.EdmItemCollection.GenerateFunctionDefinition(EdmFunction function)在System.Data.Entity.Core.Common.Utils.Memoizer 2.<>c__DisplayClass2.<Evaluate>b__0() at System.Data.Entity.Core.Common.Utils.Memoizer System.Data.Entity.Core.Common.Utils.Memoizer 2.<>c__DisplayClass2.<Evaluate>b__0() at System.Data.Entity.Core.Common.Utils.Memoizer ()

在System.Data.Entity.Core.Core.Common.Utils.Memoizer`2.Evaluate(TArg arg)在System.Data.Entity.Core.Metadata.Edm.EdmItemCollection.GetGeneratedFunctionDefinition(EdmFunction function)在System.Data.Entity.Core System.Data.Entity.Core.Query.PlanCompiler.ITreeGenerator.Visit(DbFunctionExpression e)處的.Metadata.Edm.MetadataWorkspace.GetGeneratedFunctionDefinition(EdmFunction函數)

我一直在關注該文章的答案,這要感謝他的出色解釋: LINQ to Entities無法識別方法'Double Parse(System.String)',該方法無法轉換為商店表達式

我的第一個觀察結果是這是否應該在EF映射中? 從概念上講,位置是否知道如何計算到另一個任意點的距離? 實際上,我將所有這些都放在一個名為DistanceCalculator的單獨的類中,該類獲得2個任意點並為您提供一個距離。 在實現查詢結果后,可以調用此方法。

實現中的問題是您的函數無法轉換回SQL。 EF不知道如何將那些Math。*函數轉換為SQL。 首先,將所有這些Math。*調用替換為SqlFunctions中的相應調用。 這個班有

提供公共語言運行時(CLR)方法,該方法在LINQ to Entities查詢中調用數據庫中的函數。

那應該為EF生成可用的SQL。

如果使用的是EF6 +,則可以將DistanceBetweenTwoPositions的邏輯作為SQL標量值函數移動。

更新您的EF模型並將標量值函數導入模型。

如果您以這種方式進行了映射,則可以像在查詢中一樣在查詢中使用它。

希望能有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM