web-dev-qa-db-ja.com

Entity Framework 6 Code First関数マッピング

Entity Framework 6を​​システムに統合したいのですが、問題があります。

  1. Code Firstを使用したい。他の理由でDatabase First * .edmxファイルを使用したくありません。
  2. 属性マッピング[テーブル]、[列]を使用しますが、これは正常に動作します
  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;
    }
}

ただし、例外があります。

モデル生成中に1つ以上の検証エラーが検出されました。

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

ありがとう!


はい、これは私のために動作します。ただし、スカラー関数のみ。また、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でサポートが追加されるでしょう。どんな情報も非常に役立ちます。

ありがとう!

26
Alexey

まだ試していませんが、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);
    }
}
15
Athari

必要なすべての手順は次のとおりです[テスト済み]:

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
3
Nina

ヘルパーメソッドを使用して、プリミティブ型から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

3
drew

entity Frameworkはベータ版ではないので、おそらくあなたはあなたの問題を解決したかもしれませんが、これは私の問題を解決しました linq to entityでスカラー値関数を使用する方法?

1
DanielV