无法使用ADO.NET实体框架执行存储过程。

9
我创建了一个简单的无参存储过程,如下所示。我已将存储过程导入到我的实体模型中,并创建了一个函数导入。但是模型中的函数从未被创建,我也无法使用ADO.NET实体框架执行此存储过程。我已在XML视图中打开.edmx文件,并确认没有关于此存储过程的错误。我做错了什么?难道无法从实体框架调用这样一个简单的存储过程吗?我已将导入函数的返回类型设置为“None”,因为此存储过程不需要返回任何记录集或值。
存储过程:
ALTER PROC [dbo].[Inventory_Snapshot_Create]

AS

SET NOCOUNT ON

DECLARE @Inventory_Snapshot_ID int

INSERT INTO Inventory_Snapshots (snapshot_timestamp)
VALUES (GETDATE())

SET @Inventory_Snapshot_ID = SCOPE_IDENTITY()

INSERT INTO Inventory_Snapshot_Products (inventory_snapshot_id,
    idProduct, stock)

    SELECT @Inventory_Snapshot_ID, idProduct, stock
    FROM products


SET NOCOUNT OFF

尝试执行存储过程的代码:

Dim db As New MilkModel

db.Inventory_Snapshot_Create()
7个回答

11

这是完全正确的。这里不需要什么恶劣的黑客技巧 - 你只需要阅读文档。 - Stuart

6

谢谢,pmarflee。

我来这里发布我的解决方案,同时看到了你的回复。这段代码实际上使用了实体框架的连接,并执行了我导入模型中的存储过程。微软一直在推动我们开发人员使用实体框架而不是LINQ to SQL和其他数据访问层生成器,但实际上EF还远未达到应有的水平。在未来的项目中,我不会再使用它,除非它成为更完整的解决方案。

这就是我最终采取的做法:

Dim db As New MilkModel

'==
'Begin dirty hack to execute parameterless/resultless stored
'procedure using Entity Framework (well, sort of using EF). 
'http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/44a0a7c2-7c1b-43bc-98e0-4d072b94b2ab/
'==
Dim con As DbConnection = db.Connection

con.Open()

Dim cmd As DbCommand = con.CreateCommand()

With cmd
    .CommandType = CommandType.StoredProcedure
    .CommandText = "MilkModel.Inventory_Snapshot_Create"
    .ExecuteNonQuery()
    .Dispose()
End With

con.Dispose()
'==
'End dirty hack
'==

感谢您提供的解决方法,我也无法相信您不能通过此方法调用存储过程。但正如pmarflee所说,原因是如果您正在修改EF中的表,则不应使用它。 - greektreat
2
不需要使用黑客技巧,请参考此链接:http://msdn.microsoft.com/zh-cn/library/bb896231.aspx - Daniel O

4
任何存储过程都可以通过EF调用。创建一个SP并将其添加到您的模型中。然后进入模型浏览器,右键单击sp,然后单击添加函数导入,在此处选择您的SP,并选择它返回的类型,如果它没有返回则选择“无”。如果它返回标量类型,则选择该类型,如果它返回记录集,则选择复杂类型。单击获取列信息,它将显示返回的列。单击创建新复杂类型。然后单击确定。如果它返回您的实体之一,则单击选项实体,并从列表框中选择实体类型。
现在您可以在代码中调用它。
如果它返回复杂类型,请使用以下代码:
MyEntities _entities = new MyEntities(); var p = from d in _entities.GetOrderInfo() select d;
如果它没有返回,则使用以下代码:
MyEntities _entities = new MyEntities(); _entities.Cancel_Sale(ucode, oid);
有关更多查询,请访问

http://dubeyniraj.blogspot.com/


如果您使用的是EF5及以上版本,则没有函数导入,您可以直接访问它们而无需进行函数导入。 - Niraj

3

我认为你不能将存储过程添加到EF模型中,除非它与实体的特定CRUD操作相关联。但是,您可以引用实体容器对象的Connection属性来访问EF正在使用的基础ADO.NET连接对象。然后,您可以使用传统的ADO.NET代码调用您的存储过程。


1

对于我的项目,我实际上正在使用FirebirdSql数据库,我不知道它是否适合Entity Framework,因为我使用它会出现一些问题,并且性能也不是很好。

但无论如何,如果我(函数)导入一个带有一些插入操作的存储过程,由于某种原因什么都不会发生。换句话说,如果我将这样的SP添加到我的模型(EDCX)中:

create procedure insert_stuff(thing varchar(40))
returns response(50)
as
begin
    insert into stuffs(thing) values (thing);

    response = 'done!';

    suspend;
end;

然后我这样调用它:

FirebirdContext.InsertStuff("Hi there!"); // it should return an ObjectResult<String>
FirebirdContext.SaveChanges();

实际上什么都没有发生。完全没有任何异常、结果或插入,一切都很完美,没有警告,没有编译错误。有趣的是,如果我在存储过程脚本中放置一个删除操作,删除就可以正常工作!但没有插入操作!

表非常简单,如所示,我已经导入了其他存储过程并且它们可以正常工作,但是因为它们包含查询、更新和删除操作,在插入操作时就会出现问题!这可能是 Firebird Ado.NET Provider 的一个 bug 吗?还是我需要设置一些我错过的东西?


1

如果有其他人对此感到困惑...

存储过程和实体框架的主要问题在于需要定义返回类型。例如,如果您有一个从表中返回一些行的存储过程,则需要告诉实体框架这些行的结构是什么样子的。它需要这样做才能生成所有代理类并序列化和反序列化事物。

当您转到模型 - 右键单击 - 导入函数时,可以选择存储过程,但它期望返回类型为无、标量或实体类型(即基于数据库中的表)。如果您愿意,可以添加复杂类型。右键单击模型 - 选择添加 - 复杂类型。然后定义列及其数据类型。

完成后,您刚刚创建的类将显示在上述实体类型列表下。


0
如果想避免使用DBCommand,我成功地通过使存储过程返回与实体定义匹配的某些列来完成它的工作。

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