2014-11-19 9 views
5

Ich folgte diesen Anweisungen, um meinem Entity Framework 6-Datenmodell eine Skalarfunktion hinzuzufügen. Aufruf der DB-Funktion mit Entity Framework 6

Allerdings kann ich die Funktion nicht innerhalb einer LINQ-Abfrage aufrufen, obwohl der Aufruf der Methode direkt auf dem DataContext funktioniert.

using (Entities context = new Entities()) { 
    // This works. 
    var Test1 = context.fn_GetRatingValue(8, 9, 0).FirstOrDefault(); 
    // This doesn't work. 
    var Test2 = (from r in context.MediaRatings 
       select context.fn_GetRatingValue(r.Height, r.Depth, 0)).ToList(); 
} 

Die zweite Abfrage löst diesen Fehler aus.

LINQ to Entities does not recognize the method 'System.Data.Entity.Core.Objects.ObjectResult`1[System.Nullable`1[System.Single]] fn_GetRatingValue(System.Nullable`1[System.Single], System.Nullable`1[System.Single], System.Nullable`1[System.Single])' method, and this method cannot be translated into a store expression. 

Auch der Designer gibt mir diese Warnung

Error 6046: Unable to generate function import return type of the store function 'fn_GetRatingValue'. The store function will be ignored and the function import will not be generated. 

Was mache ich falsch? Wie kann ich die Datenbankfunktion innerhalb einer LINQ-Abfrage aufrufen?

Auch wenn der Abfragecode manchmal gegen die Datenbank und manchmal im Speicher ausgeführt wird, gibt es eine Möglichkeit, die Funktion auf eine Weise aufzurufen, die in beiden Fällen funktioniert? Ich habe eine C# Version der gleichen Funktion.

Dank

Edit: Hier ist die Funktion zu verwenden, ich versuche.

public float? GetValue(float? Height, float? Depth, float ratio) { 
    if (Height != null || Depth != null) { 
     float HeightCalc = Height ?? Depth.Value; 
     float DepthCalc = Depth ?? Height.Value; 
     if (ratio < 0) 
      DepthCalc = DepthCalc + (HeightCalc - DepthCalc) * -ratio; 
     else if (ratio > 0) 
      HeightCalc = HeightCalc + (DepthCalc - HeightCalc) * ratio; 
     return (float)Math.Round(HeightCalc * DepthCalc * .12, 1); 
    } else 
     return null; 
} 

Es kann auch in einer Zeile wie folgt geschrieben werden. Diese Zeile könnte überall kopiert/eingefügt werden, aber ich würde sehr hässlichen Code erzeugen, obwohl das funktionieren könnte. Ich würde es lieber als Funktion behalten.

return (float)Math.Round(
    (Height.HasValue ? Height.Value + (ratio > 0 ? ((Depth ?? Height.Value) - Height.Value) * ratio : 0) : Depth.Value) * 
    (Depth.HasValue ? Depth.Value + (ratio < 0 ? ((Height ?? Depth.Value) - Depth.Value) * -ratio : 0) : Height.Value) 
    * .12, 1); 
+0

Keine Kommentare. Hat jemand eine Idee zu diesem Thema? –

+0

Ich habe es geschafft, die 6046-Warnung zu entfernen, indem ich alle Funktionsparametern als Kleinbuchstaben in die EDMX-Datei setzte, aber ich kann die Funktion immer noch nicht in einer Abfrage verwenden. –

Antwort

8

Ich fand die Antwort. Obwohl ich sehr wenig Dokumentation über Entity Framework 6 finden konnte, in der EdmFunctionAttribute veraltet ist, habe ich diesen Code zum Laufen gebracht.

In der EDMX-Datei muss IsComposable True sein und der CommandText muss entfernt werden. Ich brauche nur die Funktionsdeklaration ohne die Funktion Import.

Dann in einer Teilklasse meiner Datenkontext, habe ich diese Funktion

[DbFunction("NaturalGroundingVideosModel.Store", "fn_GetRatingValue")] 
public float? DbGetValue(float? height, float? depth, float ratio) { 
    List<ObjectParameter> parameters = new List<ObjectParameter>(3); 
    parameters.Add(new ObjectParameter("height", height)); 
    parameters.Add(new ObjectParameter("depth", depth)); 
    parameters.Add(new ObjectParameter("ratio", ratio)); 
    var lObjectContext = ((IObjectContextAdapter)this).ObjectContext; 
    var output = lObjectContext. 
      CreateQuery<float?>("NaturalGroundingVideosModel.Store.fn_GetRatingValue(@height, @depth, @ratio)", parameters.ToArray()) 
     .Execute(MergeOption.NoTracking) 
     .FirstOrDefault(); 
    return output; 
} 

ich die Funktion zum MediaRating Objekt hinzugefügt, damit ich es, ohne einen Verweis auf den Datenkontext aufrufen können.

var Test2 = (from r in context.MediaRatings 
    select r.DbGetValue(r.Height, r.Depth, 0)).ToList(); 

Das funktioniert!

+3

Ich habe gerade festgestellt, dass beim Erstellen von LINQ-Abfragen der DbGetValue-Code nicht einmal aufgerufen wird! Sie können also den Code in der Funktion entfernen oder ihn berechnen, ohne die Datenbank aufzurufen, da der Code nur aufgerufen wird, wenn er direkt außerhalb einer Abfrage aufgerufen wird. –

Verwandte Themen