支持EF6 Code First中的表值函数?

时间:2014-02-13 23:50:06

标签: entity-framework entity-framework-6

是否可以在EF6 Code First中拨打TVF?

我首先使用EF6数据库启动了一个新项目,EF能够将TVF导入模型并调用它。

但是更新模型变得非常耗时且有问题,因为没有RI的大型只读数据库我无法处理。

所以我尝试首先使用Power Tools逆向工程工具转换为EF6代码,以生成上下文和模型类。

不幸的是,逆向工程工具没有导入TVF。

接下来,我尝试将DBFunctions从旧的Database First DbContext复制到新的Code First DbContext,但这给了我一个错误,我的TVF: “无法解析为有效的类型或函数”。

是否可以首先为TVF创建代码Fluent映射?

如果没有,是否有解决办法?

我想我可以使用SP而不是TVF,但我希望我可以使用大多数TVF来处理我遇到的有问题的数据库。

感谢任何解决方法

6 个答案:

答案 0 :(得分:12)

现在可以了。我创建了一个自定义模型约定,允许在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/

答案 1 :(得分:9)

[测试] 使用:

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

答案 2 :(得分:5)

我可以使用下面的代码访问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();

答案 3 :(得分:2)

我实际上开始在EF6.1中查看它并且有一些适用于夜间构建的东西。检查thisthis

答案 4 :(得分:2)

我为此功能开发了一个库。你可以查看我的文章 UserTableFunctionCodeFirst。 您可以在不编写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>();
            }

这将调用您的用户定义函数并映射到实体。

答案 5 :(得分:1)

现在EntityFramework.Functions包也提供了类似的功能。这个似乎更新了。

源代码位于GitHubintroductory article解释了基本原则。