【问题标题】:Getting data from stored procedure with Entity Framework使用实体框架从存储过程中获取数据
【发布时间】:2015-11-15 10:12:35
【问题描述】:

我正在尝试使用从数据库上下文对象(使用实体框架 6.1.1)调用的动态 SQL 存储过程获取表的内容,以便填充 GridView 控件。我无法检索数据。

这是存储过程。这是为学生演示存储过程中的 SQL 注入,所以我知道这是可注入的,很好。

ALTER PROCEDURE dbo.SearchProducts
  @SearchTerm VARCHAR(max)
AS
BEGIN
  DECLARE @query VARCHAR(max)
  SET @query = 'SELECT * FROM dbo.Products WHERE Name LIKE ''%' + @SearchTerm + '%'''
  EXEC(@query)
END

后面我用来执行存储过程的C#代码是:

var db = new MyEntities();
var TEST_SEARCH_TERM = "product";
var result = db.SearchProducts(TEST_SEARCH_TERM);

MyGridView.DataSource = result;
MyGridView.DataBind();

在 Visual Studio 的数据库资源管理器中执行时,存储过程可以正常工作。但是在正在运行的 ASP.NET 应用程序中执行时,我在 DataBind() 方法中遇到异常,因为 result 返回 -1 而不是 IEnumerable DataSet 包含存储过程的 SELECT 产生的对象。

如何检索数据并填充我的GridView

【问题讨论】:

  • 在您的 edmx 中,转到 Function Imports --> SearchProducts,然后双击它。返回类型设置为什么?
  • 未设置返回类型。它是(无)。
  • 听起来需要设置为复杂。我可能建议的唯一一件事是,因为我在执行此操作时没有让 EF 给我问题,所以更改您的 * 以在 SP 中显式选择您想要的列。也许 EF 会查看它来确定您的返回类型。然后更新您的 EDMX,以便更改反映在 EF 中。
  • 注意,EF 可能很挑剔。从 EDMX 中删除存储过程并重新添加它可能是最简单的方法。我也遇到了更新问题,没有更新所有内容。以防万一您遇到其他问题。
  • 我正在尝试,似乎 EF 能够通过获取表结构并推断列名来创建复杂类型。

标签: c# asp.net sql-server entity-framework stored-procedures


【解决方案1】:

使用以下步骤解决此问题:

  1. 您需要将存储过程作为函数导入。右键单击实体模型的工作区并选择Add -> Function Import
  2. 在“添加函数导入”对话框中,输入您希望在模型中引用您的存储过程的名称,例如 Search_Products,从下拉列表中选择您的过程,然后选择该过程的返回值Entities 并从下拉列表中选择 Products
  3. 然后在后面的代码中:

    var db = new MyEntities();
    var TEST_SEARCH_TERM = "product";
    var result = db.Search_Products(TEST_SEARCH_TERM);//Search_Products is the name that you specified in Function Import dialog
    
    MyGridView.DataSource = result;
    MyGridView.DataBind();
    

您获得-1 作为结果的原因是实体框架不支持开箱即用的存储过程返回值。我认为对存储过程返回值的支持取决于实体框架的版本。此外,Entity Framework 没有丰富的存储过程支持,因为它是 ORM,而不是 SQL 替代品。

【讨论】:

  • 所有代码语言的甜蜜母亲。我不知道为什么它现在有效。我希望这保持稳定。谢谢x1000伙计。 +100 声望当之无愧。
【解决方案2】:

我以前在使用动态 SQL 的存储过程中遇到过这种情况。如果我添加行'SET FMTONLY OFF;',我已经成功使用复杂类型(请参阅https://msdn.microsoft.com/en-us/library/ms173839.aspx)到我的存储过程的顶部,然后再将其添加到 EF 模型中。使用复杂类型设置模型后,请务必删除此行。

例子:

ALTER PROCEDURE dbo.SearchProducts
  @SearchTerm VARCHAR(max)
AS
BEGIN
  SET FMTONLY OFF;
  DECLARE @query VARCHAR(max)
  SET @query = 'SELECT * FROM dbo.Products WHERE Name LIKE ''%' + @SearchTerm + '%'''
  EXEC(@query)
END

【讨论】:

  • 是的,试过了,没有帮助我。但我觉得它很有趣,因为它让我了解了 EF 的内部工作原理以及它如何获取元数据来构建结果集。
【解决方案3】:

验证您的 EDMX 是否具有返回类型: 转到 Function Imports --> SearchProducts,然后双击它。

为了利用复杂返回类型,实体框架将要求您在存储过程中显式定义列名,而不是使用 *。

修改存储过程以定义列名后,您可以更新项目中的模型。 (注意,完全删除 SP,然后将其添加回您的 edmx 可能是最佳途径。)

编辑

也许你可以像下面这样修改你的 SP:

ALTER PROCEDURE dbo.SearchProducts
  @SearchTerm VARCHAR(max)
AS
BEGIN
  SELECT * FROM dbo.Products WHERE Name LIKE '%' + @SearchTerm + '%'
END

【讨论】:

  • 在模型中尝试向这个存储过程添加复杂类型时,模型资源管理器不允许您添加它,因为“所选存储过程不返回任何列”
  • 你能像我上面那样修改它,还是必须有@query?....除了你应该特别声明你的列。
  • 所以...通过将返回类型定义为“产品”类型的实体来实现它。现在我想要的是将返回类型设为复杂类型,而不是实体。我试试你的建议。无论如何,您的解决方案有所帮助,我会在最后一次尝试后接受。
  • 我又回来了。我已经尝试过你的建议。不工作。
  • 我已将问题缩小到语句的 LIKE 部分。如果我完全删除 WHERE 条件,我会让 EF 在模型更新时自动生成一个复杂类型。如果我让 WHERE 条件但将 @SearchTerm 替换为常量字符串,则相同,EF 生成复杂类型,一切都很好。当我尝试使用该参数时,它失败了......所以我猜 EF 中的动态存储过程是不可能的?我尝试了 SETFMT ON 技巧……但仍然没有。
【解决方案4】:

您似乎已经解决了您的问题,以下链接提供了 Microsoft 的官方文档:

如何将存储过程导入实体数据模型: https://msdn.microsoft.com/en-us/library/vstudio/bb896231(v=vs.100).aspx

EF 设计器中的复杂类型: https://msdn.microsoft.com/en-gb/data/jj680147.aspx

确保您使用的是最新版本的 .net,并在对数据库进行更改时使模型保持最新。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多