LINQ to SQL -- 无法修改存储过程的返回类型

22
当我将一个特定的存储过程拖入VS 2008数据库模型设计器时,它的返回类型被设置为“none”,而且是只读的,所以我无法更改它。设计器代码显示其返回int类型,如果我手动更改它,则在下一次构建时它会被撤销。
但对于另一个(几乎相同的)存储过程,我可以很好地更改返回类型(从“自动生成的类型”到我想要的类型)。
我在两台独立的机器上都遇到了这个问题。有什么想法吗?
以下是可行的存储过程:
USE [studio]
GO
/****** Object:  StoredProcedure [dbo].[GetCourseAnnouncements]    Script Date: 05/29/2009 09:44:51 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE PROCEDURE [dbo].[GetCourseAnnouncements]
    @course int
AS
SELECT * FROM Announcements WHERE Announcements.course = @course
RETURN

而这个则不行:

USE [studio]
GO
/****** Object:  StoredProcedure [dbo].[GetCourseAssignments]    Script Date: 05/29/2009 09:45:32 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE PROCEDURE [dbo].[GetCourseAssignments]
    @course int
AS
SELECT * FROM Assignments WHERE Assignments.course = @course ORDER BY date_due ASC
RETURN

在尝试添加一个查询了该数据库中不存在的表格的存储过程时,我遇到了这个问题。 - The Muffin Man
12个回答

19

我也多次遇到这个问题,虽然我不知道是什么原因导致的,但我找到了一个非常简单的方法来解决它。它涉及手动编辑.dbml文件中的xml,但这是一个相当简单的操作。

在解决方案资源管理器中右键单击你的数据上下文的.dbml文件(不是.layout文件或designer.cs文件),并使用XML编辑器打开它。你应该能够在<Function> ... </Function>块中找到存储过程。你还应该能够在<Type> ... </Type>块中找到你想要设置为返回类型的自定义类。

第一步是要给你的自定义类一个标识符。你需要添加一个"Id"标签,就像这样,确保它在dbml文件中是唯一的:

<Type Name="MyCustomClass" Id="ID1">

第二步是告诉您的函数使用新标识的类型作为返回类型。您可以通过在<Function>块中替换类似以下行来实现:

<Return Type="System.Int32" />
"使用"
<ElementType IdRef="ID1" />

保存文件,退出并重新构建。 完成后,在设计模式下重新打开.dbml文件以验证:您的过程现在将自定义类设置为返回类型。


1
我发现我还需要编辑.designer.cs文件才能更新存储过程方法的返回类型。否则,在代码中使用存储过程方法时,它仍将返回int。 - Tarsier

15

我遇到了类似的映射问题,但我在我的情况下找到了罪魁祸首。

如果您的过程或任何被调用的子过程具有临时对象,例如

CREATE TABLE #result (
   ID INT,
   Message VARCHAR(50)
)

如果你没有选择任何这些临时对象,那么你可能会遇到麻烦。

映射器对这些临时对象存在一般性问题,因为类型可以在会话上下文中外部更改。对于映射器来说,临时对象不是类型安全的,因此它拒绝使用它们。

将它们替换为表变量,你就能解决问题了。

DECLARE @result AS TABLE (
   ID INT,
   Message VARCHAR(50)
)

1
我在想这个是否有任何文档记录,我已经搜索了整整一天才找到这个。 - CheGueVerra
我已经按照这种方式重写了我的存储过程,但没有帮助。不确定为什么... - Filip

12

我按照Tony提供的 链接,采用更好的解决方案(与Arash的答案相同)。

  • 务必阅读博客,尤其是最后一部分,因为在存储过程中添加 SET FMTONLY OFF时需要考虑一些事情。

当您添加

 SET FMTONLY OFF

在存储过程的开头加载它到DBML, LINQ2SQL会执行实际的存储过程。

为了获取正确的返回表对象类型, 所述存储过程必须在不带参数调用时返回一些内容。 这意味着:
1. 对所有输入参数设置默认值
2. 确保SP至少返回一行数据--这就是我遇到困难的地方

create table #test ( text varchar(50) );
insert into #test (text) values ('X'); -- w/o this line, return type would be Int32
select * from #test; -- SP returns something, proper object type would be generated
return;

工作正常。谢谢 :) - Thulasiram

5
好的,我找到了问题……有点。我更改了表“Assignments”的名称,但忘记更新存储过程,因此DBML设计器感到困惑。但是,即使我更新了存储过程,从DBML设计器中删除并重新添加它,它仍然无法工作!
这几乎是在这里讨论的相同问题:http://forums.asp.net/t/1231821.aspx
只有当我从数据库中删除存储过程并重新创建它,并从DBML设计器中删除它,重新编译,重新启动Visual Studio并再次添加它时,它才起作用。这是我第二次遇到Visual Studio DBML设计器的“刷新”问题……

5
我找到了一种更简单的方法,当时并不明显,但写下来后听起来很直接:
  1. 从.dbml文件的设计界面中删除存储过程
  2. 点击保存所有文件
  3. 在Server Explorer中,单击“存储过程”列表上的“刷新”
  4. 将存储过程重新添加(拖动)到.dbml文件的设计界面上
  5. 点击保存所有
  6. 点击生成
  7. 检查designer.cs代码文件,您将获得更新的C#代码,用于新版本的存储过程
请查看http://www.high-flying.co.uk/C-Sharp/linq-to-sql-can-t-update-dbml-file.html

1
我曾经遇到过同样的问题,但只有在我的存储过程使用全文搜索时才会出现。我采取了一种“欺骗”的方式来解决这个问题,即删除dbml设计器中的全文搜索语言相关内容,这样就可以完美地更改返回类型了。之后,我再次添加全文搜索语言到存储过程中,一切都运行得非常完美!希望这能帮到你。

1

解决此问题的方法是:

  1. 在存储过程开头添加 "set fmtonly off;" 语句。
  2. 添加完该语句后,让 DBML 为您的存储过程生成代码。

如果 DBML 代码中存储过程的返回类型仍然是 'int',请注释掉整个存储过程的代码,并创建一个新的 SELECT 语句,其返回字段的类型和名称与原始 SELECT 语句相匹配,然后再次生成 DBML 代码。这样就可以解决问题了!


1

感谢@Rubenz,我也在存储过程中使用了全文搜索(FTS),你的步骤很有效。

我注释了存储过程中的FTS部分,将存储过程添加到.dbml中,然后将FTS部分取消注释恢复原样。


0

我意识到这是一个旧问题,但上面的建议指引了我正确的方向,但在我的情况下并没有起作用。最终,我按照上面建议的方法使用 Visual Studio 中的 XML 编辑器编辑了 dbml 文件。

一旦进入文件,查找存储过程的函数部分。您很可能看不到定义返回类型的 ElementType 部分。我开始从另一个函数(存储过程)中编辑字段,发现这太繁琐,并可能引入问题。

我决定删除 ElementType 中的所有列定义 - 但保留 ElementType 部分并保存该文件。然后我从设计器中删除了存储过程并重新添加它。然后它填充了 ElementType 中的正确列。运行得非常好。



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