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

时间:2009-05-29 16:48:39

标签: linq-to-sql stored-procedures asp.net-3.5

当我将特定存储过程拖到VS 2008 dbml设计器中时,它会显示返回类型设置为“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

12 个答案:

答案 0 :(得分:19)

我也曾多次看到这个问题,虽然我不知道是什么原因引起的,但我遇到了一个很简单的方法。它涉及在.dbml文件中手动编辑xml,但这是一个非常简单的编辑。

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

第一步是为自定义类提供标识符。您可以通过添加“Id”标记来实现此目的,确保它在dbml文件中是唯一的:

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

第二步是告诉你的函数使用新的ID类型作为返回类型。您可以通过替换 <Function>块中看起来像

的行来完成此操作
<Return Type="System.Int32" />

<ElementType IdRef="ID1" />

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

答案 1 :(得分:13)

我有类似的映射问题,但我发现了我的罪魁祸首。

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

CREATE TABLE #result (
   ID INT,
   Message VARCHAR(50)
)
然后你就麻烦了,即使你没有选择这些临时任何东西。

映射器具有这些临时对象的一般问题,因为可以在会话上下文中的过程之外更改类型。对于映射器,临时对象不是类型安全的,他拒绝使用它们。

用表变量替换它们,然后你又恢复了业务

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

答案 2 :(得分:9)

我跟随link provided by Tony寻求更好的解决方案(与Arash相同的答案)

  • 请阅读博客,尤其是最后一部分,因为在您的存储过程中添加 SET FMTONLY OFF 时需要考虑一下。

添加

 SET FMTONLY OFF

在存储过程的开头并将其加载到DBML,
LINQ2SQL将执行实际的存储过程。

要获得正确的返回表对象类型,
所谓的存储过程在调用w / o参数时必须返回一些内容 这意味着:
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;

答案 3 :(得分:5)

好的,我发现了问题......有点儿。我更改了“Assignments”表的名称并忘记更新存储的procudure,因此DBML设计者感到困惑。即使我更新了存储过程后,将其从DBML设计器中删除并读取它,它也无法正常工作!

这与此处讨论的问题几乎相同:http://forums.asp.net/t/1231821.aspx

只有当我从数据库中删除存储过程并重新创建它,并从DBML设计器中删除它,重新编译,重新启动Visual Studio并再次添加它时,它才有效。这是我第二次遇到Visual Studio DBML设计器的“刷新”问题......

答案 4 :(得分:5)

我设法制定了一种更简单的方法,当时并不明显,但写下来时听起来很直接:

  1. 从.dbml文件的设计图面中删除存储过程
  2. 点击保存所有文件
  3. 在“存储过程”列表中的“服务器资源管理器”中单击“刷新”
  4. 将存储过程添加(拖动)回到.dbml文件的设计图面
  5. 点击全部保存
  6. 点击构建
  7. 检查designer.cs代码文件,您将获得新版本存储过程的更新C#代码
  8. 检查http://www.high-flying.co.uk/C-Sharp/linq-to-sql-can-t-update-dbml-file.html

答案 5 :(得分:1)

我有同样的问题,但只有当我的sp使用FTS时才会发生,我所做的是“欺骗”dbml设计器,我删除了fts语言的东西并且工作完美,现在我可以更改返回类型。后来我去sp并再次添加fts并且完美地工作! 希望这有帮助。

答案 6 :(得分:1)

解决此问题的方法是:

  1. 添加“set fmtonly off;”到存储过程的开头。
  2. 添加该语句后,获取DBML将为您的存储过程生成代码。
  3. 如果存储过程的返回类型在DBML代码中仍为“int”,则注释存储过程的整个代码,创建一个新的SELECT语句,其返回的字段类型和名称与原始的SELECT语句匹配,并获取DBML再次重新生成代码。它必须工作!

答案 7 :(得分:1)

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

我从存储过程中注释了FTS部分,将存储过程添加到.dbml,然后将FTS部分取消注释回原始部分。

答案 8 :(得分:0)

当使用sql用户定义类型作为存储过程中的参数

时,也会发生这种情况

http://alejandrobog.wordpress.com/2009/09/23/linq-to-sql-%e2%80%94-can%e2%80%99t-modify-return-type-of-stored-procedure/

答案 9 :(得分:0)

答案 10 :(得分:0)

好吧,我不想在Designer.cs代码中更改任何内容,我知道有一个不同的问题,它与我的存储过程无关(我还没有使用临时表)。

简单地从数据库中删除sp并更新模型根本没有帮助。创建的新模型仍然存在同样的问题......

我发现由于某种原因,我的sp的副本是在DatabaseModel中创建的 - &gt;功能导入。

我做了什么,删除了功能导入中的重复对象并更新了模型。它奏效了!

此致 克里斯

答案 11 :(得分:0)

我意识到这是一个古老的问题,但是以上建议为我指明了正确的方向,但不适用于我的情况。如上所述,我最终使用Visual Studio中的XML编辑器编辑了dbml文件。

在文件中,找到存储过程的“功能”部分。您很可能看不到“元素类型”部分,该部分定义了返回类型。我开始从另一个函数(存储过程)中编辑字段,发现这太麻烦了,可能会引起问题。

我决定从ElementType中删除所有Column定义-但保留ElementType部分并保存文件。然后,我从设计器中删除了存储过程,然后重新添加了它。然后在ElementType中填写正确的列。做工精美。