如何使用EntityFramework调用存储过程?

38

我已从MySQL数据库生成了EF4模型,并包含了存储过程和表格。

我知道如何对EF执行常规的插入/更新/提取/删除操作,但我找不到我的存储过程。

这就是我所期望的:

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));

附注:如果需要,我可以更改EF版本

编辑1:

CREATE DEFINER=`106228`@`%` PROCEDURE `updateGame`(
    inId INT,
    inName VARCHAR(255),
    inDescription TEXT,
    inYearPublished DATETIME,
    inMinPlayers INT,
    inMaxPlayers INT,
    inPlayingTime VARCHAR(127)
)
7个回答

74

一种方法是使用DbContext的Database属性:

SqlParameter param1 = new SqlParameter("@firstName", "Frank");
SqlParameter  param2 = new SqlParameter("@lastName", "Borland");
context.Database.ExecuteSqlCommand("sp_MyStoredProc @firstName, @lastName", 
                              param1, param2);

EF5 肯定支持这个功能。


我不明白,为什么我要硬编码存储过程名称?我在生成模型时已经添加了它们。它们不应该只是作为上下文对象的方法存在吗? - Ivy
2
是的,如果您尚未将其链接到模型并且希望获得原始访问权限,则应该这样做 ;) - Quinton Bernhardt
3
这段话的意思是:这只是将存储过程作为非查询方式执行,它无法读取任何返回的表格。 - user586399

12

您需要使用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类,该类代表查询返回的结果表。 - user586399

5

将存储过程导入到模型中后,您可以在模型浏览器中的 Context.Store/Stored Procedures 部分中右键单击它,然后单击 Add Function Import。如果需要一个复杂类型作为结果,您可以在那里创建它。


尝试过这个,但它没有生成带参数的方法?不确定如何放置参数? - Ivy
1
当过程有参数时,它们将被添加。 - user1908061
它对我有用,使用框架4。您能展示一下存储过程的创建语句吗?(只包含参数) - ESG
所以,你的代码里没有任何奇怪的东西。它应该支持参数,我不确定为什么不行。你能否尝试使用只有几个参数的过程,比如3个整数,看看它会做什么? - ESG
谢谢!是的,我可能不得不手动操作,因为我无法更新MySQL服务器。 - Ivy
显示剩余2条评论

3

根据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>();
}

我正在开发一个存储过程框架这里),你可以像下面的测试方法一样调用它...

[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)
    {
    }
}

如果这两种方法有用的话?

2
基本上,您只需使用存储过程映射将过程映射到实体即可。
一旦映射完成,您可以使用EF中添加项目的常规方法,它将使用您的存储过程。
请参见:此链接以获取演示。
结果将添加如下所示的实体(实际上将使用您的存储过程)。
using (var ctx = new SchoolDBEntities())
        {
            Student stud = new Student();
            stud.StudentName = "New sp student";
            stud.StandardId = 262;

            ctx.Students.Add(stud);
            ctx.SaveChanges();
        }

尽管有很多答案,但这是OP正在寻找的唯一答案。 - Gert Arnold

1
这是一个使用Entity Framework查询MySQL存储过程的示例。
这是我在MySQL中定义的存储过程:
CREATE PROCEDURE GetUpdatedAds (
    IN curChangeTracker BIGINT
    IN PageSize INT
) 
BEGIN
   -- select some recored...
END;

这是我使用Entity Framework查询的方式:

 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#字符串插值来构建我的查询字符串。

1

这是我最近为我的数据可视化应用程序所做的事情,该应用程序具有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 + "\'");

        }

我不明白,为什么我要硬编码存储过程的名称?我在生成模型时已经添加了它们。它们不应该只是作为上下文对象的方法存在吗? - Ivy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接