EF6コードファーストでTVFを呼び出すことは可能ですか?
最初にEF6データベースを使用して新しいプロジェクトを開始しましたが、EFはTVFをモデルにインポートして、問題なく呼び出すことができました。
しかし、モデルの更新は非常に時間がかかり、RIのない大きな読み取り専用データベースでは問題が発生しました。
そこで、最初にPower Toolsリバースエンジニアリングツールを使用してEF6コードに変換し、コンテキストクラスとモデルクラスを生成しようとしました。
残念ながら、リバースエンジニアリングツールはTVFをインポートしませんでした。
次に、DBFunctionsを古いDatabase FirstDbContextから新しいCodeFirst DbContextにコピーしようとしましたが、TVFが「有効なタイプまたは関数に解決できません」というエラーが発生しました。
TVFのコードファーストFluentマッピングを作成することは可能ですか?
そうでない場合、回避策はありますか?
TVFの代わりにSPを使用できると思いますが、問題のあるDBを処理するために、ほとんどの場合TVFを使用できることを望んでいました。
回避策のアイデアをありがとう
これが可能になりました。 EF6.1のCodeFirstでストア関数を使用できるようにするカスタムモデル規則を作成しました。規則はNuGetで利用できます http://www.nuget.org/packages/EntityFramework.CodeFirstStoreFunctions 。すべての詳細を含むブログ投稿へのリンクは次のとおりです。 http://blog.3d-logic.com/2014/04/09/support-for-store-functions-tvfs-and-stored-procs- in-entity-framework-6-1 /
[テスト済み]使用:
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 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
以下のコードでTVFにアクセスできました。これはEF6で機能します。モデルのプロパティ名は、データベースの列名と一致する必要があります。
List<MyModel> data =
db.Database.SqlQuery<MyModel>(
"select * from dbo.my_function(@p1, @p2, @p3)",
new SqlParameter("@p1", new System.DateTime(2015,1,1)),
new SqlParameter("@p2", new System.DateTime(2015, 8, 1)),
new SqlParameter("@p3", 12))
.ToList();
私はこの機能のためのライブラリを開発しました。 serTableFunctionCodeFirst に関する私の記事を確認できます。 SQLクエリを記述せずに関数を使用できます。
更新
まず、上記のライブラリへの参照を追加する必要があります。次に、関数のパラメータクラスを作成する必要があります。このクラスには、任意の数とタイプのパラメーターを含めることができます
public class TestFunctionParams
{
[CodeFunctionAttributes.FunctionOrder(1)]
[CodeFunctionAttributes.Name("id")]
[CodeFunctionAttributes.ParameterType(System.Data.SqlDbType.Int)]
public int Id { get; set; }
}
次に、DbContextに次のプロパティを追加して、関数を呼び出し、プロパティにマップする必要があります。
[CodeFunctionAttributes.Schema("dbo")] // This is optional as it is set as dbo as default if not provided.
[CodeFunctionAttributes.Name("ufn_MyFunction")] // Name of function in database.
[CodeFunctionAttributes.ReturnTypes(typeof(Customer))]
public TableValueFunction<TestFunctionParams> CustomerFunction { get; set; }
次に、以下のように関数を呼び出すことができます。
using (var db = new DataContext())
{
var funcParams = new TestFunctionParams() { Id = 1 };
var entity = db.CustomerFunction.ExecuteFunction(funcParams).ToList<Customer>();
}
これにより、ユーザー定義関数が呼び出され、エンティティにマップされます。
同様のことが EntityFramework.Functions パッケージによっても提供されるようになりました。これはもっと最新のようです。