8

我在SQL Server 2008中有一个叫做'GetPrices'的存储过程,它带有一个名为'StoreIDs'的表值参数。存储过程中的表值参数和实体框架4.0

这是我为这个TVP创建的类型:

CREATE TYPE integer_list_tbltype AS TABLE (n int) 

我想从我的实体框架调用SP。但是,当我尝试将存储过程添加到EDM时,出现以下错误:

函数'GetPrices'在参数索引2处有一个参数'StoreIDs',其数据类型'表类型'不是支持的。该功能被排除在外。

这有什么解决方法吗?有什么想法吗?

法比奥

回答

1

由于您无法使用表格参数,因此请尝试传入CSV sting,并让存储过程将其拆分成行。

有很多方法可以在SQL Server中拆分字符串。本文介绍了几乎每一个方法的优点和缺点:

"Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog

你需要创建一个分裂的功能。这是一个分裂的功能如何使用:

SELECT 
    * 
    FROM YourTable        y 
    INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value 

I prefer the number table approach to split a string in TSQL但也有许多方法来拆分在SQL Server中的字符串,见前面的链接,这说明各的优点和缺点。

对于数字表的方法来工作,你需要做的这一次表的设置,这将创建一个包含从1到10000行的表Numbers

SELECT TOP 10000 IDENTITY(int,1,1) AS Number 
    INTO Numbers 
    FROM sys.objects s1 
    CROSS JOIN sys.objects s2 
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number) 

一旦Numbers表格设置,创建此分割功能:

CREATE FUNCTION [dbo].[FN_ListToTable] 
(
    @SplitOn char(1)  --REQUIRED, the character to split the @List string on 
    ,@List  varchar(8000)--REQUIRED, the list to split apart 
) 
RETURNS TABLE 
AS 
RETURN 
( ---------------- 
    --SINGLE QUERY-- --this will not return empty rows 
    ---------------- 
    SELECT 
     ListValue 
     FROM (SELECT 
        LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue 
        FROM (
          SELECT @SplitOn + @List + @SplitOn AS List2 
         ) AS dt 
         INNER JOIN Numbers n ON n.Number < LEN(dt.List2) 
        WHERE SUBSTRING(List2, number, 1) = @SplitOn 
      ) dt2 
     WHERE ListValue IS NOT NULL AND ListValue!='' 
); 
GO 

您现在可以轻松地拆分CSV字符串转换成表格和加入或使用它,但是你需要:

CREATE PROCEDURE YourProcedure 
(
    @CSV_Param varchar(1000) 
) 
AS 

--just an example of what you can do 
UPDATE t 
    SET Col1=... 
    FROM dbo.FN_ListToTable(',',@CSV_Param) dt 
     INNER JOIN TBL_USERS     t ON CAST(dt.value AS INT)=t.id 

GO 
1

您可以使用ObjectContext.Connection属性use ADO.NET来创建和使用您的表值参数。这可能是不可接受的,但如果你想使用这个令人敬畏的SQL Server 2008功能和EF,这似乎是你只是选择。

然后,您可以选择使用方法扩展部分生成的对象上下文,以照顾所有低级ADO.NET内容。像这样:

public partial class FriendsOnBoardEntities : ObjectContext 
{ 
    public IList<int> GetPrices(int n) 
    { 
     // 'low-level' ado.net stuff here. 
     // Use SqlParameters, SqlCommand and what not... 
    } 
} 
1

我同意在这种情况下传递CSV sting是最好的解决方案。 我想建议更简单的方法来分割csv字符串,而不用创建表格和函数,通过使用CTE:

declare @separator char(1); 
set @separator = ','; 

;with baseCte as 
(select left(@ValueList, charindex(@separator, @ValueList) - 1) as Value, 
substring(@ValueList, charindex(@separator, @ValueList) + 1, len(@ValueList)) 
as rest 
union all 
select left(rest, charindex(@separator, rest) - 1) as Value, 
substring(rest, charindex(@separator, rest) + 1, len(rest)) from baseCte 
where len(rest) > 1 
) 
select Value from baseCte 
OPTION (MAXRECURSION 0);