entity framework6代码优先function映射

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

但有例外:

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

 Edm.String: : The namespace 'String' is a system namespace and cannot be used by other schemas. Choose another namespace name. 

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

EF版本:6.0.0-beta1-20521

谢谢!


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

  IQueryable MyFunction() 

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

但仍然没有运气:

  model.Compile(); // ERROR 

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

谢谢!

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

这是代码的样子:

 public class MyContext : DbContext { public DbSet Customers { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Add(new FunctionsConvention("dbo")); } [DbFunction("MyContext", "CustomersByZipCode")] public IQueryable CustomersByZipCode(string zipCode) { var zipCodeParameter = zipCode != null ? new ObjectParameter("ZipCode", zipCode) : new ObjectParameter("ZipCode", typeof(string)); return ((IObjectContextAdapter)this).ObjectContext .CreateQuery( string.Format("[{0}].{1}", GetType().Name, "[CustomersByZipCode](@ZipCode)"), zipCodeParameter); } public ObjectResult GetCustomersByName(string name) { var nameParameter = name != null ? new ObjectParameter("Name", name) : new ObjectParameter("Name", typeof(string)); return ((IObjectContextAdapter)this).ObjectContext. ExecuteFunction("GetCustomersByName", nameParameter); } } 

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

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

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

 var edmType = GetStorePrimitiveType(model, PrimitiveTypeKind.String); 

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

以下是[测试]所需的所有步骤:

 Install-Package EntityFramework.CodeFirstStoreFunctions 

为输出结果声明一个类:

 public class MyCustomObject { [Key] public int Id { get; set; } public int Rank { get; set; } } 

在DbContext类中创建一个方法

 [DbFunction("MyContextType", "SearchSomething")] public virtual IQueryable SearchSomething(string keywords) { var keywordsParam = new ObjectParameter("keywords", typeof(string)) { Value = keywords }; return (this as IObjectContextAdapter).ObjectContext .CreateQuery( "MyContextType.SearchSomething(@keywords)", keywordsParam); } 

 public DbSet SearchResults { get; set; } 

到你的DbContext类

添加重写的OnModelCreating方法:

 modelBuilder.Conventions .Add(new CodeFirstStoreFunctions.FunctionsConvention("dbo")); 

现在你可以用这样的表值函数调用/ join:

 CREATE FUNCTION SearchSomething ( @keywords nvarchar(4000) ) RETURNS TABLE AS RETURN (SELECT KEY_TBL.RANK AS Rank, Id FROM MyTable LEFT JOIN freetexttable(MyTable , ([MyColumn1],[MyColumn2]), @keywords) AS KEY_TBL ON MyTable.Id = KEY_TBL.[KEY] WHERE KEY_TBL.RANK > 0 ) GO 

现在entity framework不是测试版,所以也许你解决了你的问题,但是这个解决了我的问题如何使用标量值函数和linq实体?