8

Ho una stored procedure in SQL Server 2008 denominata "GetPrices" con un parametro con valori di tabella denominato "StoreIDs".Parametro con valori di tabella in Stored procedure e Entity Framework 4.0

Questo è il tipo che ho creato per questo TVP:

CREATE TYPE integer_list_tbltype AS TABLE (n int) 

vorrei chiamare la SP dal mio Entity Framework. Ma quando provo ad aggiungere la stored procedure all'EDM, ottengo il seguente errore:

La funzione 'GetPrices' ha un parametro 'StoreIDs' all'indice di parametro 2 che ha un tipo di dati 'tipo di tabella' che non è supportato. La funzione è stata esclusa.

C'è qualche soluzione? qualche idea?

Fabio

risposta

1

Dato che non è possibile utilizzare un parametro di tabella, provare a passare in una stringa CSV e fare in modo che la stored procedure la divida in righe.

Esistono molti modi per suddividere la stringa in SQL Server. Questo articolo riguarda i pro ei contro di quasi ogni metodo:

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

È necessario creare una funzione di divisione. Questo è come una funzione di split può essere utilizzato:

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 ma ci sono numerosi modi per dividere le stringhe in SQL Server, vedere il link precedente, il che spiega i pro ei contro di ciascuna.

Per il metodo Numbers tavolo di lavoro, è necessario fare questa configurazione tavolo una volta, che creerà una tabella Numbers che contiene le righe da 1 a 10.000:

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) 

Una volta che la tabella di Numbers è impostato , creare questa funzione split:

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 

si può ora facilmente dividere una stringa CSV in una tabella e di unirsi a esso o utilizzarlo tuttavia è necessario:

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

È possibile utilizzare la proprietà ObjectContext.Connection su use ADO.NET per creare e utilizzare i parametri con valori di tabella. Questo potrebbe non essere accettabile, ma se vuoi usare questa fantastica funzionalità di SQL Server 2008 e EF, sembra che tu sia solo una scelta.

È quindi possibile scegliere di estendere il contesto dell'oggetto parzialmente generato con il metodo per occuparsi di tutto il materiale ADO.NET di basso livello.Come questo:

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

Sono d'accordo che il passaggio in una puntura CSV è la soluzione migliore in questo caso. Vorrei proporre un modo più semplice per dividere la stringa csv, senza creare tabelle e funzioni, utilizzando 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); 
Problemi correlati