如何使用 EntityFramework 调用存储过程?
Posted
技术标签:
【中文标题】如何使用 EntityFramework 调用存储过程?【英文标题】:How to call Stored Procedures with EntityFramework? 【发布时间】:2012-12-25 05:50:33 【问题描述】:我从 mysql 数据库生成了一个 EF4 模型,并包含了 StoredProcedures 和 Tables。
我知道如何对 EF 进行常规的插入/更新/获取/删除操作,但我找不到我的 StoredProcedures。
这正是我所希望的:
using (Entities context = new Entities())
context.MyStoreadProcedure(Parameters);
编辑1:
这是没有 EF 时的样子:
sqlStr = "CALL updateGame(?,?,?,?,?,?,?)";
commandObj = new OdbcCommand(sqlStr, mainConnection);
commandObj.Parameters.Add("@id,", OdbcType.Int).Value = inGame.id;
commandObj.Parameters.Add("@name", OdbcType.VarChar, 255).Value = inGame.name;
commandObj.Parameters.Add("@description", OdbcType.Text).Value = ""; //inGame.description;
commandObj.Parameters.Add("@yearPublished", OdbcType.DateTime).Value = inGame.yearPublished;
commandObj.Parameters.Add("@minPlayers", OdbcType.Int).Value = inGame.minPlayers;
commandObj.Parameters.Add("@maxPlayers", OdbcType.Int).Value = inGame.maxPlayers;
commandObj.Parameters.Add("@playingTime", OdbcType.VarChar, 127).Value = inGame.playingTime;
return Convert.ToInt32(executeScaler(commandObj));
PS。如果需要,我可以更改 EF 版本
编辑1:
CREATE DEFINER=`106228`@`%` PROCEDURE `updateGame`(
inId INT,
inName VARCHAR(255),
inDescription TEXT,
inYearPublished DATETIME,
inMinPlayers INT,
inMaxPlayers INT,
inPlayingTime VARCHAR(127)
)
【问题讨论】:
【参考方案1】:一种方法是使用 DbContext 之外的 Database 属性:
SqlParameter param1 = new SqlParameter("@firstName", "Frank");
SqlParameter param2 = new SqlParameter("@lastName", "Borland");
context.Database.ExecuteSqlCommand("sp_MyStoredProc @firstName, @lastName",
param1, param2);
EF5 绝对支持。
【讨论】:
我不明白,为什么要硬编码 SP 名称?我在生成模型时添加了它们?不应该只是作为方法存在于 Context 对象的某个地方吗? 是的,如果你没有将它链接到你的模型并且你想要 raw 访问,这就是这样做的方法;) 这只是将存储的过程作为非查询执行。它无法读取任何返回的表【参考方案2】:您已使用 SqlQuery 函数并指示实体映射结果。
我发送一个示例来执行此操作:
var oficio= new SqlParameter
ParameterName = "pOficio",
Value = "0001"
;
using (var dc = new PCMContext())
return dc.Database
.SqlQuery<ProyectoReporte>("exec SP_GET_REPORTE @pOficio",
oficio)
.ToList();
【讨论】:
你必须声明你的ProyectoReporte
类来代表查询返回的结果表【参考方案3】:
将存储过程导入模型后,您可以右键单击它(从模型浏览器中的Context.Store
/Stored Procedures
部分),然后单击Add Function Import
。如果你需要一个复杂的类型,你可以在那里创建它。
【讨论】:
试过了,但它没有生成带参数的方法?不知道如何输入参数? 当程序有参数时,就会被添加。 它适用于我,使用框架 4。你能显示该过程的创建语句吗? (仅带参数) 所以,你没有什么奇怪的东西。它确实应该支持参数,我不确定为什么不支持。你能用一个只有几个参数的过程来试试,比如 3 个整数,看看它做了什么? 我尝试添加一个只有一个参数但它不起作用【参考方案4】:基于 OP 的原始请求,能够像这样调用存储过程...
using (Entities context = new Entities())
context.MyStoreadProcedure(Parameters);
Mindless passenger 有一个项目,允许您从这样的实体框架调用存储过程......
using (testentities te = new testentities())
//-------------------------------------------------------------
// Simple stored proc
//-------------------------------------------------------------
var parms1 = new testone() inparm = "abcd" ;
var results1 = te.CallStoredProc<testone>(te.testoneproc, parms1);
var r1 = results1.ToList<TestOneResultSet>();
...我正在研究一个stored procedure framework (here),您可以像下面显示的我的测试方法之一那样调用它...
[TestClass]
public class TenantDataBasedTests : BaseIntegrationTest
[TestMethod]
public void GetTenantForName_ReturnsOneRecord()
// ARRANGE
const int expectedCount = 1;
const string expectedName = "Me";
// Build the paraemeters object
var parameters = new GetTenantForTenantNameParameters
TenantName = expectedName
;
// get an instance of the stored procedure passing the parameters
var procedure = new GetTenantForTenantNameProcedure(parameters);
// Initialise the procedure name and schema from procedure attributes
procedure.InitializeFromAttributes();
// Add some tenants to context so we have something for the procedure to return!
AddTenentsToContext(Context);
// ACT
// Get the results by calling the stored procedure from the context extention method
var results = Context.ExecuteStoredProcedure(procedure);
// ASSERT
Assert.AreEqual(expectedCount, results.Count);
internal class GetTenantForTenantNameParameters
[Name("TenantName")]
[Size(100)]
[ParameterDbType(SqlDbType.VarChar)]
public string TenantName get; set;
[Schema("app")]
[Name("Tenant_GetForTenantName")]
internal class GetTenantForTenantNameProcedure
: StoredProcedureBase<TenantResultRow, GetTenantForTenantNameParameters>
public GetTenantForTenantNameProcedure(
GetTenantForTenantNameParameters parameters)
: base(parameters)
如果这两种方法中的任何一种都好?
【讨论】:
【参考方案5】:基本上,您只需使用存储过程映射将过程映射到实体。
映射后,您使用常规方法在 EF 中添加项目,它将使用您的存储过程。
请参阅:This Link 了解演练。 结果将添加一个像这样的实体(实际上将使用您的存储过程)
using (var ctx = new SchoolDBEntities())
Student stud = new Student();
stud.StudentName = "New sp student";
stud.StandardId = 262;
ctx.Students.Add(stud);
ctx.SaveChanges();
【讨论】:
尽管有所有答案,但这是 OP 正在寻找的唯一答案。【参考方案6】:这是我最近为具有 2008 SQL 数据库的数据可视化应用程序所做的。在这个例子中,我收到了一个从存储过程返回的列表:
public List<CumulativeInstrumentsDataRow> GetCumulativeInstrumentLogs(RunLogFilter filter)
EFDbContext db = new EFDbContext();
if (filter.SystemFullName == string.Empty)
filter.SystemFullName = null;
if (filter.Reconciled == null)
filter.Reconciled = 1;
string sql = GetRunLogFilterSQLString("[dbo].[rm_sp_GetCumulativeInstrumentLogs]", filter);
return db.Database.SqlQuery<CumulativeInstrumentsDataRow>(sql).ToList();
然后在我的情况下这个扩展方法用于一些格式:
public string GetRunLogFilterSQLString(string procedureName, RunLogFilter filter)
return string.Format("EXEC 0 1,2, 3, 4", procedureName, filter.SystemFullName == null ? "null" : "\'" + filter.SystemFullName + "\'", filter.MinimumDate == null ? "null" : "\'" + filter.MinimumDate.Value + "\'", filter.MaximumDate == null ? "null" : "\'" + filter.MaximumDate.Value + "\'", +filter.Reconciled == null ? "null" : "\'" + filter.Reconciled + "\'");
【讨论】:
我不明白,为什么要硬编码 SP 名称?我在生成模型时添加了它们?不应该只是作为方法存在于 Context 对象的某个地方吗?【参考方案7】:这是一个使用实体框架查询 MySQL 过程的示例
这是我在 MySQL 中存储过程的定义:
CREATE PROCEDURE GetUpdatedAds (
IN curChangeTracker BIGINT
IN PageSize INT
)
BEGIN
-- select some recored...
END;
这就是我使用实体框架查询它的方式:
var curChangeTracker = new SqlParameter("@curChangeTracker", MySqlDbType.Int64).Value = 0;
var pageSize = new SqlParameter("@PageSize", (MySqlDbType.Int64)).Value = 100;
var res = _context.Database.SqlQuery<MyEntityType>($"call GetUpdatedAds(curChangeTracker, pageSize)");
请注意,我使用C# String Interpolation 来构建我的查询字符串。
【讨论】:
以上是关于如何使用 EntityFramework 调用存储过程?的主要内容,如果未能解决你的问题,请参考以下文章
从另一个不工作的线程调用存储过程 c#, EntityFramework
使用带有 C# 的 Entity Framework 6 调用现有的存储过程
如何使用 AutoMapper 使用 EntityFramework 使用嵌套列表更新对象?