簡體   English   中英

Entity Framework 6 Code First 函數映射

[英]Entity Framework 6 Code First function mapping

我想將 Entity Framework 6 集成到我們的系統中,但有問題。

  1. 我想使用代碼優先。 由於其他原因,我不想使用 Database First *.edmx 文件。
  2. 我使用屬性映射 [Table], [Column] 這很好用
  3. 數據庫有許多用戶定義的函數,我需要在 Linq To Entities 查詢中使用它們。

問題是:

我無法通過 [Table]、[Column] 等屬性映射函數。 只有 1 個屬性可用 [DbFunction],需要 *.edmx 文件。

我可以在 *.edmx 文件中進行函數映射,但這意味着我不能對實體使用屬性映射:[表]、[列]。 *.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;
    }
}

但有例外:

在模型生成期間檢測到一個或多個驗證錯誤:

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

問題出在“edmType”變量中。 我無法為函數正確創建 ReturnType。 有人可以建議我如何將功能添加到模型中嗎? 添加函數的接口是暴露的,應該可以,但是web中沒有關於這種情況的信息。 可能有人知道 Entity Framework 團隊何時會為 Line To Sql 之類的函數實現屬性映射。

EF 版本:6.0.0-beta1-20521

謝謝!


是的,這對我有用。 但僅適用於標量函數。 我還需要 map 函數,它返回 IQueryable:

 IQueryable<T> 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包含public mapping API Moozzyk 使用這個新功能為 EntityFramework CodeFirst實現了存儲函數。

代碼如下所示:

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

以下是所需的所有步驟 [已測試]:

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<MyCustomObject> SearchSomething(string keywords)
{
   var keywordsParam = new ObjectParameter("keywords", typeof(string)) 
                           { 
                              Value = keywords 
                            };
    return (this as IObjectContextAdapter).ObjectContext
    .CreateQuery<MyCustomObject>(
     "MyContextType.SearchSomething(@keywords)", keywordsParam);
}

添加

public DbSet<MyCustomObject> SearchResults { get; set; }

到您的 DbContext 類

添加覆蓋的OnModelCreating方法:

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

現在你可以調用/加入一個表值函數,如下所示:

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

您可以使用輔助方法從原始類型獲取 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

現在實體框架不是測試版,所以也許你解決了你的問題,但這個解決了我的問題如何在 linq to entity 中使用標量值函數?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM