Ich habe eine Tabelle mit Dezimalzahlen (und anderen Typen), die als Strings gespeichert sind. Ich möchte eine Linq-Abfrage für den Datenbankkontext schreiben, der in eine Datenbank-Cast und nicht eine lokale Besetzung (aus Leistungsgründen) übersetzt wird.
Dieses nicht funktionierende Beispiel ist konzeptionell das, was ich erreichen möchte.
using ( var context = new MyContext() )
{
return context.SomeTable
.Select(o => new { o.Id, (decimal)o.SomeString });
}
Dies ist ein schlechter Weg , um es zu erreichen, da es die Konvertierung auf der Anwendungsseite ausführen wird.
using ( var context = new MyContext() )
{
return context.SomeTable
.Select(o => new { o.Id, o.SomeString })
.ToList()
.Select(o => new { o.Id, Convert.ToDecimal(o.SomeString) });
}
Ich glaube, der Weg zu gehen ist mit DbFunctions, aber ich kann keinen Weg finden, es mit Code First zu verwenden.
Dies ist die Teilantwort, aber ich konnte die Dokumentation nicht finden, die ich benötigte, um den Teil zu finalisieren, in dem ich definiere, was diese Funktion auf dem SQL-Server macht.
[DbFunction("MyContext", "ConvertToDecimal")]
public static decimal ConvertToDecimal(string s)
{
throw new Exception("Direct calls are not supported.");
}
.
using ( var context = new MyContext() )
{
return context.SomeTable
.Select(o => new { o.Id, ConvertToDecimal(o.SomeString) });
}
Wenn ich eine Edmx- getriebene Alternative verwenden würde, wäre dies der fehlende Teil:
<Function Name="ConvertToDecimal" ReturnType="Edm.Decimal">
<Parameter Name="s" Type="Edm.String" />
<DefiningExpression>
CAST(s AS decimal(22,6))
</DefiningExpression>
</Function>
Ich verwende Entity Framework 6 Code zuerst.
Ich fand die Lösung mit einigen Informationen aus diesem Thema.
Wie ich in der ursprünglichen Frage angenommen habe, hatte ich die ersten 2 Teile unten. Der letzte Teil besteht darin, im DbModel die Funktionen, die Sie aufrufen möchten, und deren Verwendung zu registrieren. Es gibt mehr als eine Möglichkeit, dies zu tun, aber ich habe eine Konvention verwendet
public class MyFunctionsConvetion : IStoreModelConvention<EntityContainer>
{
public void Apply(EntityContainer item, DbModel model)
{
//Get the Edm Model from the DbModel
EdmModel storeModel = model.GetStoreModel();
//Delare your parameters name, edm type and mode (You can ignore this if you use a parameter-less function)
List<FunctionParameter> Parameters = new List<FunctionParameter>();
Parameters.Add(FunctionParameter.Create("StringValue", GetStorePrimitiveType(model, PrimitiveTypeKind.String), ParameterMode.In));
//Same thing goes for the return type(s) (Why is it a list? Perhaps you can return tables? I haven't tested however since it is no use to me)
List<FunctionParameter> ReturnParameters = new List<FunctionParameter>();
ReturnParameters.Add(FunctionParameter.Create("ReturnValue", GetStorePrimitiveType(model, PrimitiveTypeKind.Decimal), ParameterMode.ReturnValue));
//Create the payload and fill the required information alone with the parameter lists we declared
EdmFunctionPayload payload = new EdmFunctionPayload();
payload.IsComposable = true;
payload.Schema = "dbo";
payload.StoreFunctionName = "ConvertToDecimal";
payload.ReturnParameters = ReturnParameters;
payload.Parameters = Parameters;
//Create the function with it's payload
EdmFunction function = EdmFunction.Create("ConvertToDecimal", "MyContext", DataSpace.SSpace, payload, new MetadataProperty[] { });
//Add it to the model
storeModel.AddItem(function);
}
//Little helper method to get the primitive type based on the database provider
private EdmType GetStorePrimitiveType(DbModel model, PrimitiveTypeKind typeKind)
{
return model
.ProviderManifest
.GetStoreType(TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(typeKind)))
.EdmType;
}
}
Dann fügen wir dem Modell in der OnModelCreating-Methode die Konvention hinzu
modelBuilder.Conventions.Add<MyProject.MyConventions.MyFunctionsConvention>();
Hinweis: Der Code könnte sauberer und DRY-mäßiger geschrieben sein, aber der Einfachheit halber wollte ich ihn so posten und Sie so organisieren, wie Sie es für richtig halten.