Entity framework 首先在EF6代码中支持表值函数?

Entity framework 首先在EF6代码中支持表值函数?,entity-framework,entity-framework-6,Entity Framework,Entity Framework 6,可以先在EF6代码中调用TVF吗 我首先使用EF6数据库启动了一个新项目,EF能够将一个TVF导入到模型中,并称之为良好 但是,更新模型变得非常耗时,而且对于我一直在处理的没有RI的大型只读数据库来说,这是一个问题 因此,我尝试首先使用Power Tools反向工程工具转换为EF6代码,以生成上下文和模型类 不幸的是,反向工程工具没有导入TVFs 接下来,我尝试将DBFunctions从旧数据库First DbContext复制到新的Code First DbContext,但这给了我一个错误,

可以先在EF6代码中调用TVF吗

我首先使用EF6数据库启动了一个新项目,EF能够将一个TVF导入到模型中,并称之为良好

但是,更新模型变得非常耗时,而且对于我一直在处理的没有RI的大型只读数据库来说,这是一个问题

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

不幸的是,反向工程工具没有导入TVFs

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

是否可以为TVFs创建代码优先的流畅映射

如果没有,是否有解决方案

我想我可以用SPs而不是TVF,但我希望我可以用TVF来处理我遇到的有问题的DB


感谢大家围绕这些想法所做的工作

我实际上是在EF6.1中开始研究它的,并且有一些东西是在夜间构建的。签出。

现在这是可能的。我创建了一个自定义模型约定,允许在EF6.1中的CodeFirst中使用存储函数。该公约可在NuGet上获得。以下是包含所有详细信息的博客帖子链接:

我可以使用下面的代码访问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();
列表数据=
db.Database.SqlQuery(
“从dbo.my_函数(@p1、@p2、@p3)中选择*”,
新的SqlParameter(“@p1”,新的System.DateTime(2015,1,1)),
新的SqlParameter(“@p2”,新的System.DateTime(2015,8,1)),
新的SqlParameter(“@p3”,12))
.ToList();

我已经为这个功能开发了一个库。你可以看我的文章 . 您可以在不编写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; }
[CodeFunctionAttributes.Schema(“dbo”)]//这是可选的,因为如果没有提供,它将被设置为默认的dbo。
[CodeFunctionAttributes.Name(“ufn_MyFunction”)]//数据库中函数的名称。
[CodeFunctionAttribute.ReturnTypes(typeof(Customer))]
public TableValueFunction CustomerFunction{get;set;}
然后您可以如下调用您的函数

using (var db = new DataContext())
            {
                var funcParams = new TestFunctionParams() { Id = 1 };
                var entity = db.CustomerFunction.ExecuteFunction(funcParams).ToList<Customer>();
            }
使用(var db=new DataContext())
{
var funcParams=newtestfunctionparams(){Id=1};
var entity=db.CustomerFunction.ExecuteFunction(funcParams.ToList();
}
这将调用用户定义的函数并映射到实体。

[已测试] 使用:

为输出结果声明一个类:

    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);
}
现在你可以打电话/加入 表值函数如下所示:

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

该软件包现在也提供了类似的功能。这一条似乎更符合时代潮流


源代码在上提供,并解释了基本原理。

我不这么认为,至少这是我仍然首先使用模型的原因,但要解决大型模型的问题,只需不将所有内容导入一个模型,而是使用更小的特定于域的代理/客户端。显然,您可以:感谢zahorak的想法,如果我找不到代码优先的解决方法,我可能会先切换到数据库优先的方法。我的意图是使用逆向工程工具只导入我需要的TVF,并且只使用这些工具访问我无法从代码优先上下文更改的大的、糟糕的、丑陋的db。TheVedge,那篇文章首先讨论数据库,使用EDMX模型,我需要从代码优先,这意味着没有EDMX模型,改为使用Fluent API映射的DbContext。@对不起,读取速度太快。目前这是不可能的,它被推迟到EF6之后:我刚刚尝试在EF6.1的官方版本中使用CodeFirstFunctions,我可以证明它工作得很好。这里似乎有一些注意事项,但我能够创建一个可组合的函数,该函数可以毫无困难地返回复杂类型。项目中提供的端到端单元测试是如何完成测试的一个完美示例。感谢您提供的信息-很高兴听到这个消息。我正在准备一个NuGet软件包,这样你就可以“开箱即用”(即不必自己编译)地使用它,还准备了一篇关于如何使用它的博客文章。你能分享更多关于注意事项的信息吗?他们是因为缺少文档而产生bug还是更多?我遇到的唯一问题是我的TVF有可为空的参数。这导致了一些我记不起来的错误,但它让我进入了代码,在代码中我注意到了一些类似的事情。我指的就是这些。当我将函数的C#定义更改为使用常规标量参数时,一切都很好。谢谢。我确实需要添加对可空参数的支持。“我本来不打算为alpha做这件事,但看起来我应该这么做。@Erictered-昨天我发布了公约的beta版。可为null的参数类型的问题现已修复。还有一些新特性,如支持存储过程返回多个结果集或支持标量UDF—请看这里:谢谢!我必须将base.OnModelCreating(modelBuilder)添加到OnModelCreating,或者添加迁移,发现大量更改。@Pawel这有什么原因不能与Npgsql一起工作吗?您发布的代码甚至与实体框架无关。是的,任何事情都可以使用SQL查询来完成,但通常有EF方法和SQL查询方法来完成。在有EF方式的情况下
public DbSet<MyCustomObject> SearchResults { get; set; }
 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