Табличный параметр в хранимой процедуре и Entity Framework 4.0 - PullRequest
8 голосов
/ 15 мая 2010

У меня есть хранимая процедура в SQL Server 2008 под названием «GetPrices» с табличным параметром «StoreIDs».

Это тип, который я создал для этого TVP:

CREATE TYPE integer_list_tbltype AS TABLE (n int)

Я хотел бы вызвать SP из моей Entity Framework. Но когда я пытаюсь добавить хранимую процедуру в EDM, я получаю следующую ошибку:

Функция «GetPrices» имеет параметр «StoreIDs» в параметре index 2 с типом данных «тип таблицы», который не поддерживается. Функция была исключена.

Есть ли обходной путь? Есть мысли?

Fabio

Ответы [ 4 ]

1 голос
/ 20 ноября 2012

Я согласен с тем, что в данном случае наилучшим решением является передача в поле CSV. Я хотел бы предложить более простой способ разделения строки 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);
1 голос
/ 15 мая 2010

Поскольку вы не можете использовать параметр таблицы, попробуйте передать строку CSV, и хранимая процедура разделит его на строки.

Есть много способов разбить строку в SQL Server. В этой статье рассматриваются плюсы и минусы практически каждого метода:

"Массивы и списки в SQL Server 2005 и более поздних версиях, когда параметры табличных значений не обрезают его", Эрланд Соммарског

Вам необходимо создать функцию разделения. Вот как можно использовать функцию разделения:

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

Я предпочитаю подход с использованием таблиц чисел для разделения строки в TSQL , но существует множество способов разделения строк в SQL Server, см. Предыдущую ссылку, которая объясняет за и против каждого из них.

Чтобы метод таблицы чисел сработал, необходимо выполнить настройку единой таблицы, которая создаст таблицу Numbers, содержащую строки от 1 до 10000:

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 голос
/ 07 ноября 2011

Вы можете использовать свойство ObjectContext.Connection, чтобы использовать 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...
    }
}
0 голосов
/ 15 мая 2010

Возможно, вы захотите проголосовать за на Microsoft Connect

Обновление: MS больше не использует Connect для функций. Они используют его только для сообщений об ошибках. Чтобы проголосовать за функцию EF, вам нужно перейти на сайт EF User Voice .

Чтобы проголосовать за этот конкретный вопрос в User Voice, перейдите по ссылке .

...