2014-11-19 18 views
5

Ho seguito queste istruzioni per aggiungere una funzione scalare al modello di dati Entity Framework 6. How to use scalar-valued function with linq to entity?Chiamata alla funzione DB con Entity Framework 6

Tuttavia, non sono in grado di chiamare la funzione all'interno di una query LINQ, sebbene chiamare il metodo direttamente su DataContext funzioni.

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(); 
} 

La seconda query genera questo errore.

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. 

Inoltre, il progettista mi sta dando questo avvertimento

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. 

Che cosa sto facendo di sbagliato? Come posso chiamare la funzione del database all'interno di una query LINQ?

Inoltre, se il codice della query a volte viene eseguito sul database e talvolta in memoria, esiste un modo per chiamare la funzione in un modo che funzioni in entrambi i casi? Ho una versione C# della stessa funzione.

Grazie

Edit: Ecco la funzione che sto cercando di utilizzare.

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; 
} 

Può anche essere scritto in una riga come questa. Questa linea potrebbe essere copiata/incollata ovunque io abbia bisogno di usarlo ma questo produrrebbe un codice molto brutto, anche se potrebbe funzionare. Preferisco tenerlo come una funzione.

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

Nessun commento. Qualcuno ha qualche idea su questo? –

+0

Sono riuscito a rimuovere l'avviso 6046 inserendo tutti i nomi dei parametri funzione in minuscolo nel file EDMX, ma non riesco ancora a utilizzare la funzione all'interno di una query. –

risposta

8

Ho trovato la risposta. Anche se potrei trovare pochissima documentazione su Entity Framework 6 in cui EdmFunctionAttribute è obsoleto, ho ottenuto questo codice per funzionare.

Nel file EDMX, IsComposable deve essere True e il CommandText deve essere rimosso. Ho bisogno solo della dichiarazione di funzione senza la funzione import.

Poi, in una classe parziale del mio contesto dati, ho creato questa funzione

[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; 
} 

Ho aggiunto la funzione all'oggetto MediaRating così posso chiamarla senza bisogno di un riferimento al contesto dati.

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

Questo funziona!

+3

Ho appena realizzato che quando si creano query LINQ, il codice DbGetValue non viene nemmeno chiamato! Quindi è possibile rimuovere il codice nella funzione o calcolarlo senza chiamare il database, in quanto il codice viene chiamato solo quando viene chiamato direttamente al di fuori di una query. –

Problemi correlati