实体框架6代码优先功能映射

Ale*_*xey 27 c# entity-framework sql-function ef-code-first entity-framework-6

我想将Entity Framework 6集成到我们的系统中,但是有问题.

  1. 我想使用Code First.出于其他原因,我不想使用Database First*.edmx文件.
  2. 我使用属性映射[表],[列],这工作正常
  3. 数据库有许多用户定义的函数,我需要在Linq To Entities查询中使用它们.

问题是:

我不能通过像[Table],[Column]这样的属性来映射函数.只有1个属性可用[DbFunction],它需要*.edmx文件.

我可以在*.edmx文件中映射函数,但这意味着我不能使用实体的属性映射:[Table],[Column].必须在*.edmx或属性中填充映射.

我尝试通过以下代码创建DbModel并添加函数:

public static class Functions
{
    [DbFunction("CodeFirstNamespace", "TestEntity")]
    public static string TestEntity()
    {
        throw new NotSupportedException();
    }
}


public class MyContext : DbContext, IDataAccess
{
    protected MyContext (string connectionString)
        : base(connectionString, CreateModel())
    {
    }

    private static DbCompiledModel CreateModel()
    {
        var dbModelBuilder = new DbModelBuilder(DbModelBuilderVersion.Latest);
        dbModelBuilder.Entity<Warehouse>();
        var dbModel = dbModelBuilder.Build(new DbProviderInfo("System.Data.SqlClient", "2008"));

        var edmType = PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String);
        var payload =
            new EdmFunctionPayload
            {
                Schema = "dbo",
                ParameterTypeSemantics = ParameterTypeSemantics.AllowImplicitConversion,
                IsComposable = true,
                IsNiladic = false,
                IsBuiltIn = false,
                IsAggregate = false,
                IsFromProviderManifest = true,
                StoreFunctionName = "TestEntity",
                ReturnParameters =
                    new[]
                    {
                        FunctionParameter.Create("ReturnType", edmType, ParameterMode.ReturnValue)
                    }
            };

        var function = EdmFunction.Create("TestEntity", "CodeFirst", DataSpace.CSpace, payload, null);
        dbModel.DatabaseMapping.Model.AddItem(function);
        var compiledModel = dbModel.Compile();       // Error happens here
        return compiledModel;
    }
}
Run Code Online (Sandbox Code Playgroud)

但有例外:

在模型生成期间检测到一个或多个验证错误:

Edm.String: : The namespace 'String' is a system namespace and cannot be used by other schemas. Choose another namespace name.
Run Code Online (Sandbox Code Playgroud)

问题出在"edmType"变量中.我无法正确创建函数的ReturnType.任何人都可以建议我如何在模型中添加功能?添加功能的界面是暴露的,所以它应该能够做到,但是在这种情况下web中没有信息.可能有人知道Entity Framework团队何时会为Line To Sql这样的函数实现属性映射.

EF版本:6.0.0-beta1-20521

谢谢!


是的,这适合我.但仅适用于标量函数.我也需要map函数,它返回IQueryable:

 IQueryable<T> MyFunction()
Run Code Online (Sandbox Code Playgroud)

其中T是EntityType或RowType或任何类型.我完全不能这样做(EF版本是6.0.2-21211).我认为这应该以这种方式工作:

private static void RegisterEdmFunctions(DbModel model)
{
    var storeModel = model.GetStoreModel();
    var functionReturnValueType = storeModel.EntityTypes.Single(arg => arg.Name == "MyEntity").GetCollectionType();
    var payload =
        new EdmFunctionPayload
        {
            IsComposable = true,
            Schema = "dbo",
            StoreFunctionName = "MyFunctionName",
            ReturnParameters =
                new[]
                { 
                    FunctionParameter.Create("ReturnValue", functionReturnValueType, ParameterMode.ReturnValue)
                },
            Parameters =
                new[]
                {
                    FunctionParameter.Create("MyFunctionInputParameter", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32), ParameterMode.In)
                }
        };
    storeModel.AddItem(EdmFunction.Create(
        payload.StoreFunctionName,
        "MyFunctionsNamespace",
        DataSpace.SSpace,
        payload,
        payload.Parameters.Select(arg => MetadataProperty.Create(arg.Name, arg.TypeUsage, null)).ToArray()));
}
Run Code Online (Sandbox Code Playgroud)

但仍然没有运气:

  model.Compile();  // ERROR 
Run Code Online (Sandbox Code Playgroud)

有可能吗?可能步骤不对?可能会在EF 6.1上添加支持.任何信息都非常有用.

谢谢!

Ath*_*ari 15

尚未尝试过,但Entity Framework 6.1包含公共映射API.Moozzyk 使用这一新功能为EntityFramework CodeFirst实现了Store Functions.

这是代码的样子:

public class MyContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Add(new FunctionsConvention<MyContext>("dbo"));
    }

    [DbFunction("MyContext", "CustomersByZipCode")]
    public IQueryable<Customer> CustomersByZipCode(string zipCode)
    {
        var zipCodeParameter = zipCode != null ?
            new ObjectParameter("ZipCode", zipCode) :
            new ObjectParameter("ZipCode", typeof(string));

        return ((IObjectContextAdapter)this).ObjectContext
            .CreateQuery<Customer>(
                string.Format("[{0}].{1}", GetType().Name, 
                    "[CustomersByZipCode](@ZipCode)"), zipCodeParameter);
    }

    public ObjectResult<Customer> GetCustomersByName(string name)
    {
        var nameParameter = name != null ?
            new ObjectParameter("Name", name) :
            new ObjectParameter("Name", typeof(string));

        return ((IObjectContextAdapter)this).ObjectContext.
            ExecuteFunction("GetCustomersByName", nameParameter);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 好主意!我找到了解决方案,并在此处将其作为问题/答案发布:http://stackoverflow.com/questions/29198416/using-ef6-store-functions-for-entityframework-codefirst-can-i-return-a-custom -t希望这有助于其他人 (3认同)

小智 3

您可以使用辅助方法从原始类型获取 Store 类型:

    public static EdmType GetStorePrimitiveType(DbModel model, PrimitiveTypeKind typeKind)
    {
        return model.ProviderManifest.GetStoreType(TypeUsage.CreateDefaultTypeUsage(
            PrimitiveType.GetEdmPrimitiveType(typeKind))).EdmType;
    }
Run Code Online (Sandbox Code Playgroud)

在您的示例中,您必须更改返回参数的类型:

var edmType = GetStorePrimitiveType(model, PrimitiveTypeKind.String);
Run Code Online (Sandbox Code Playgroud)


我在这里找到了我需要的帮助: http://entityframework.codeplex.com/discussions/466706