使用用户定义函数和 Code First 方法






4.89/5 (4投票s)
本文介绍如何将实体框架代码优先方法与用户自定义表值函数结合使用。
引言
如今,广泛的社区都在使用实体框架,其中大多数人熟悉代码优先方法。 使用代码优先方法可以提高代码的模块化程度,并使其易于维护。 与数据库优先方法相比,实体框架目前尚未提供直接与用户自定义函数通信的直接方法。
背景
在我处理其中一个项目时,出现了一个需求,即我需要直接将实体框架与用户自定义函数进行通信。 毫无疑问,可以通过多种方式实现,例如使用以下代码
Database.SqlQuery<MyModel>("select * from usr_func()");
但是,我们希望使用更清晰、更有结构的代码来处理此函数。 因此,我决定编写一个库,其中我可以实现自己的自定义逻辑,以使此功能更具模块化和结构化。 因此,我查阅了不同的博客,并找到了 aureolin 撰写的《代码优先存储过程》博客(https://codeproject.org.cn/script/Membership/View.aspx?mid=254563)。 我下载了它的最新版本,并通过进行重大更改,最终成功了。
Using the Code
以下是使用 SQL Server 创建的简单表值函数
CREATE FUNCTION ufn_MyFunction
(
@id int
)
RETURNS TABLE
AS
RETURN
(
SELECT * from tbl_Customer where Id = @id
)
GO
此过程将 @id
作为参数,并根据 id 返回表记录。 这只是一个示例,实际实现可以接受任何类型或不接受任何参数,并且可以返回包含大量逻辑的查询。
现在让我们看一下使用代码优先方法映射此函数的代码。
首先,创建一个类来传递此函数的参数。 因此,我们使用以下代码创建它
public class TestFunctionParams
{
[CodeFunctionAttributes.FunctionOrder(1)]
[CodeFunctionAttributes.Name("id")]
[CodeFunctionAttributes.ParameterType(System.Data.SqlDbType.Int)]
public int Id { get; set; }
}
在这里,我们提到了函数顺序,因为在按顺序传递函数参数非常重要。 因此,如果有多个参数,则必须添加它们的顺序才能传递到函数中。 此外,我还编写了许多其他属性来处理不同的操作,例如参数的名称及其类型。
现在,我们将通过在 DbContext
类的构造函数中添加以下代码来初始化我们的库。
public DataContext()
: base("name=SqlConn")
{
this.InitializeTableFunctions();
}
现在,我们将把我们的函数作为数据上下文类中的一个属性添加,如下所示
[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; }
现在,整个 db 上下文将如下所示
public class DataContext : DbContext
{
public DataContext()
: base("name=SqlConn")
{
System.Data.Entity.Database.SetInitializer<DataContext>(null);
this.InitializeTableFunctions();
}
public DbSet<Customer> Customers { get; set; }
[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; }
}
因此,我们这边一切都准备好了。 现在,我们可以使用以下代码非常轻松地调用此函数
static void Main(string[] args)
{
using (var db = new DataContext())
{
var funcParams = new TestFunctionParams() { Id = 1 };
var entity = db.CustomerFunction.ExecuteFunction(funcParams).ToList<Customer>();
}
}
函数的最终结果将返回到对象中,并转换为列表并映射到模型。 这样,我们可以添加可以接受任意数量和任意类型参数的函数(我们还可以使用 SqlDbType.Structured
使用表值参数),并将其映射到我们的模型。
关注点
我认为实体框架是一项很棒的技术,通过使用它,我们可以创建更用户友好的应用程序,这些应用程序易于维护。 我尽力使这个库更易于使用,但如果您发现需要任何更改,可以使这个库更有用,那么欢迎您提出建议。
历史
- 版本 1.0:初始发布