Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用自定义DBF函数将字符串转换为十进制_C#_Linq_Entity Framework_Entity Framework 6 - Fatal编程技术网

C# 如何使用自定义DBF函数将字符串转换为十进制

C# 如何使用自定义DBF函数将字符串转换为十进制,c#,linq,entity-framework,entity-framework-6,C#,Linq,Entity Framework,Entity Framework 6,我有一个以字符串形式保存小数(和其他类型)的表。我想在数据库上下文上编写一个Linq查询,该查询将转换为数据库强制转换而不是本地强制转换(出于性能原因) 这个不工作的示例在概念上就是我想要实现的 using ( var context = new MyContext() ) { return context.SomeTable .Select(o => new { o.Id, (decimal)o.SomeString }); } 这是一种不好的方法,因为它将在应

我有一个以字符串形式保存小数(和其他类型)的表。我想在数据库上下文上编写一个Linq查询,该查询将转换为数据库强制转换而不是本地强制转换(出于性能原因)

这个不工作的示例在概念上就是我想要实现的

using ( var context = new MyContext() )
{
    return context.SomeTable
        .Select(o => new { o.Id, (decimal)o.SomeString });
}
这是一种不好的方法,因为它将在应用程序端运行转换

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) });
}
我认为应该使用DbFunctions,但我找不到一种方法首先将其与代码一起使用

这是部分答案,但我还没有找到完成定义此函数在SQL server上的功能部分所需的文档

[DbFunction("MyContext", "ConvertToDecimal")]
public static decimal ConvertToDecimal(string s)
{
    throw new Exception("Direct calls are not supported.");
}

如果我使用的是Edmx驱动的替代方案,这将是缺少的部分:

<Function Name="ConvertToDecimal" ReturnType="Edm.Decimal">
    <Parameter Name="s" Type="Edm.String" />
    <DefiningExpression>
        CAST(s AS decimal(22,6))
    </DefiningExpression>
</Function>

以十进制(22,6)形式转换

我首先使用的是Entity Framework 6代码。

我认为您不能按照当前版本,用户定义的函数是代码优先中尚不支持的元素之一。

我利用主题中的一些信息找到了解决方案

就像我在原始问题中假设的那样,我把前两部分都记下来了。最后一部分是在DbModel中注册希望访问的函数以及如何使用它们。有不止一种方法可以做到这一点,但我使用了一个惯例

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;
    }
}
公共类MyFunctions转换:IStoreModelConvention
{
公共无效应用(EntityContainer项,DbModel模型)
{
//从DbModel中获取Edm模型
EdmModel storeModel=model.GetStoreModel();
//Dela是您的参数名称、edm类型和模式(如果使用无参数函数,则可以忽略此项)
列表参数=新列表();
Parameters.Add(FunctionParameter.Create(“StringValue”、GetStorePrimitiveType(model、PrimitiveTypeKind.String)、ParameterMode.In));
//返回类型也是一样(为什么它是一个列表?也许你可以返回表?但是我没有测试过,因为它对我没有用)
List ReturnParameters=新列表();
添加(FunctionParameter.Create(“ReturnValue”,GetStorePrimitiveType(model,PrimitiveTypeKind.Decimal),ParameterMode.ReturnValue));
//创建有效负载并用我们声明的参数列表单独填写所需信息
EdmFunctionPayload有效载荷=新的EdmFunctionPayload();
payload.IsComposable=true;
payload.Schema=“dbo”;
payload.StoreFunctionName=“ConvertToDecimal”;
payload.ReturnParameters=返回参数;
有效载荷。参数=参数;
//使用有效载荷创建函数
EdmFunction=EdmFunction.Create(“ConvertToDecimal”、“MyContext”、DataSpace.SSpace、有效负载、新MetadataProperty[]{});
//将其添加到模型中
storeModel.AddItem(函数);
}
//基于数据库提供程序获取基元类型的小助手方法
私有EdmType GetStorePrimitiveType(DbModel模型,PrimitiveTypeKind)
{
回归模型
.ProviderManifest
.GetStoreType(TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetedPrimitiveType(typeKind)))
.EdmType;
}
}
然后,我们在OnModelCreating方法中将约定添加到模型中

modelBuilder.Conventions.Add<MyProject.MyConventions.MyFunctionsConvention>();
modelBuilder.Conventions.Add();

注意:代码可以更干净,也可以写得干干净净,但为了简单起见,我想像这样发布它,让您按照自己认为合适的方式组织它。

有任何文档支持这一说法吗?不久前我从某个论坛上听说这是EF6的一个新特性。如果你能证实你的陈述,我将接受这个答案,然后继续。@Pluc不,根本没有文档,因为它不受支持。EF 6的一项新功能是SP的insert/udpate等功能。您是否有任何参考资料支持这项新功能的声明?因为文档中的规范没有这样的内容:如果有,我会链接它。正如我所说,这只是一个模糊的记忆,我认为这是可能的,因为EF6。我想我是在梦中看到的。我会让这个问题持续一个小时,只是为了确定一下。谢谢你的意见。@Pluc最后,很遗憾,EF进展缓慢。所有的希望似乎都失去了;)我希望他们能快点。。。。而不是像即将到来的索引属性那样进入无用的方向。我只是设法做到了我想要的。我将在大约一个小时后发布一个关于如何做的答案。我只是想指出(因为我在这个问题上获得了+1票),这个解决方案使用了EF6.1以来不推荐的方法。这可能是一个很快的改变,但由于它仍然像这样工作,我没有时间去详细说明。
modelBuilder.Conventions.Add<MyProject.MyConventions.MyFunctionsConvention>();