Come utilizzare DbContext.Database.SqlQuery <TElement> (sql, params) con stored procedure? Codice EF First CTP5


254

Ho una stored procedure che ha tre parametri e ho provato a utilizzare quanto segue per restituire i risultati:

context.Database.SqlQuery<myEntityType>("mySpName", param1, param2, param3);

All'inizio ho provato a utilizzare SqlParameteroggetti come parametri ma questo non ha funzionato e ho lanciato un SqlExceptioncon il seguente messaggio:

La procedura o la funzione "mySpName" prevede il parametro "@ param1", che non è stato fornito.

Quindi la mia domanda è come puoi utilizzare questo metodo con una stored procedure che prevede parametri?

Grazie.


Quale versione di SQL Server stai utilizzando? Ho problemi con il codice che funziona nel 2008 in modalità compat (90), ma quando lo eseguo contro il 2005 non riesce con un errore di sintassi.
Gats

4
@ Gats - Ho avuto lo stesso problema con SQL 2005. Aggiungere "EXEC" prima del nome della procedura memorizzata. Ho pubblicato queste informazioni qui per riferimento futuro: stackoverflow.com/questions/6403930/…
Dan Mork

Risposte:


395

È necessario fornire le istanze SqlParameter nel modo seguente:

context.Database.SqlQuery<myEntityType>(
    "mySpName @param1, @param2, @param3",
    new SqlParameter("param1", param1),
    new SqlParameter("param2", param2),
    new SqlParameter("param3", param3)
);

3
Come faresti funzionare questo metodo con i tipi nullable? L'ho provato con decimali nullable, ma quando i decimali sono nulli ottengo errori che dicono che il parametro è mancante. Tuttavia, il metodo indicato di seguito da @DanMork funziona.
Paul Johnson

2
Il passaggio al DbNull.Valueposto dei nulli risolve il problema?
Alireza

30
È inoltre possibile utilizzare la sintassi \ @ p # per evitare di utilizzare SqlParameter come in context.Database.SqlQuery <myEntityType ("mySpName \ @ p0, \ @ p1, \ @ p2", param1, param2, param3). Fonte: msdn.microsoft.com/en-US/data/jj592907 . (Nota: doveva usare \ @ per evitare le notifiche utente, dovrebbe essere letto senza la barra rovesciata.)
Marco

3
Se si utilizzano parametri DateTime, è necessario specificare anche il tipo di parametro, non solo il nome e il valore. Ad esempio: dbContext.Database.SqlQuery <Invoice> ("spGetInvoices @dateFrom, @dateTo", new SqlParameter {ParameterName = "dateFrom", SqlDbType = SqlDbType.DateTime, Value = startDate}, new SqlParameter = "ParameterName" SqlDbType = SqlDbType.DateTime, Value = endDate}); Un'altra cosa importante è rispettare l'ordine dei parametri.
Francisco Goldenstein

puoi gentilmente controllare cosa sto facendo di sbagliato Ho seguito la tua guida ma nessun effetto stackoverflow.com/questions/27926598/…
Toxic

129

Inoltre, puoi utilizzare il parametro "sql" come identificatore di formato:

context.Database.SqlQuery<MyEntityType>("mySpName @param1 = {0}", param1)

Ho dovuto votare questo. Sebbene non sia stata accettata come risposta, è molto più facile scrivere una soluzione rispetto a quella selezionata come risposta.
Nikkoli

10
Questa sintassi mi preoccupa un po '. Sarebbe suscettibile a SQL injection? Presumo che EF stia eseguendo "EXEC mySpName @ Param1 =", e sarebbe possibile inviare "x 'GO [script dannoso]" e causare alcuni problemi?
Tom Halladay

10
@TomHalladay nessun rischio di SQL injection: il metodo citerà comunque ed eviterà i parametri in base al loro tipo, lo stesso dei parametri dello stile @. Quindi, per un parametro stringa, dovresti utilizzare "SELECT * FROM Users WHERE email = {0}" senza virgolette nella tua istruzione.
Ross McNab

nel mio caso abbiamo molti parametri opzionali per SP e non funzionava chiamate con SqlParameters ma questo formato fa il trucco, dovevo solo aggiungere "EXEC" all'inizio. Grazie.
Onur Topal

1
Questa risposta è utile se devi specificare parametri per un proc con parametri opzionali. Esempio che non funziona: ProcName @optionalParam1 = @opVal1, @optionalParam2 = @opVal2 Esempio che funziona:ProcName @optionalParam1 = {0}, @optionalParam2 = {1}
Garrison Neely

72

Questa soluzione è (solo) per SQL Server 2005

Ragazzi, siete dei salvavita, ma come ha detto @Dan Mork, dovete aggiungere EXEC al mix. Quello che mi stava facendo inciampare era:

  • "EXEC" prima del nome Proc
  • Virgole tra i parametri
  • Togliendo '@' nelle definizioni dei parametri (non sono sicuro che il bit sia richiesto).

:

context.Database.SqlQuery<EntityType>(
    "EXEC ProcName @param1, @param2", 
    new SqlParameter("param1", param1), 
    new SqlParameter("param2", param2)
);

21
+1. Nessuna delle risposte con votazione più alta include exec, ma posso confermare che ottengo un'eccezione se la ometto.
Jordan Grey

Grazie, ho ricevuto un errore, ho aggiunto EXEC e l'errore è sparito. La parte strana era se facessi context.Database.SqlQuery <EntityType> ("ProcName '" + param1 + "', '" + param2 + "'"); ha funzionato, ma se ho aggiunto parametri non ha funzionato fino a quando non ho aggiunto la parola chiave EXEC.
Solmead

2
FYI: non richiedo la execparola chiave. +1 per la rimozione della @ sui parametri, che mi incasina sempre.
Nathan Koop

+1, mi mancava EXEC e continuavo a ricevere SqlExceptions con il messaggio: sintassi non corretta vicino a "procName".
A. Murray

1
@Ziggler sei nel 2005 o più recente? La parola chiave EXEC è stata principalmente un problema per quelli di noi contro il 2005.
Tom Halladay

15
return context.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
new object[] { param1, param2, param3 });

//O

using(var context = new MyDataContext())
{
return context.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
new object[] { param1, param2, param3 }).ToList();
}

//O

using(var context = new MyDataContext())
{
object[] parameters =  { param1, param2, param3 };

return context.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
parameters).ToList();
}

//O

using(var context = new MyDataContext())
{  
return context.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
param1, param2, param3).ToList();
}

per me funziona per Assembly EntityFramework.dll, v4.4.0.0
Thulasiram

2
se stai usando using (var context = new MyDataContext ()) allora .ToList () è obbligatorio.
Thulasiram

Ho passato un po 'di tempo a scoprire che .ToList () è obbligatorio per ottenere un set di risultati corretto.
Halim

8

La maggior parte delle risposte è fragile perché si basa sull'ordine dei parametri dell'SP. Meglio nominare i parametri di Stored Proc e dare valori parametrizzati a quelli.

Per utilizzare i parametri denominati quando si chiama il proprio SP, senza preoccuparsi dell'ordine dei parametri

Utilizzo di parametri denominati di SQL Server con ExecuteStoreQuery ed ExecuteStoreCommand

Descrive l'approccio migliore. Meglio della risposta di Dan Mork qui.

  • Non si basa sulla concatenazione di stringhe e non si basa sull'ordine dei parametri definiti nell'SP.

Per esempio:

var cmdText = "[DoStuff] @Name = @name_param, @Age = @age_param";
var sqlParams = new[]{
   new SqlParameter("name_param", "Josh"),
   new SqlParameter("age_param", 45)
};

context.Database.SqlQuery<myEntityType>(cmdText, sqlParams)

Sembra che "params" sia una parola chiave riservata, quindi non credo che tu possa usarla in questo modo. Altrimenti questa è stata una risposta utile per me. Grazie!
ooXei1sh

@ ooXei1sh - risolto, utilizzando la sqlParamsvariabile
Don Cheadle

si può premettere ad essa @ per usare una parola riservata, ma davvero non si dovrebbe
StingyJack

6
db.Database.SqlQuery<myEntityType>("exec GetNewSeqOfFoodServing @p0,@p1,@p2 ", foods_WEIGHT.NDB_No, HLP.CuntryID, HLP.ClientID).Single()

o

db.Database.SqlQuery<myEntityType>(
    "exec GetNewSeqOfFoodServing @param1, @param2", 
    new SqlParameter("param1", param1), 
    new SqlParameter("param2", param2)
);

o

var cmdText = "exec [DoStuff] @Name = @name_param, @Age = @age_param";
var @params = new[]{
   new SqlParameter("name_param", "Josh"),
   new SqlParameter("age_param", 45)
};

db.Database.SqlQuery<myEntityType>(cmdText, @params)

o

db.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
new object[] { param1, param2, param3 }).ToList();

3

Uso questo metodo:

var results = this.Database.SqlQuery<yourEntity>("EXEC [ent].[GetNextExportJob] {0}", ProcessorID);

Mi piace perché mi limito a inserire Guids and Datetimes e SqlQuery esegue tutta la formattazione per me.


1

La risposta di @Tom Halladay è corretta con la menzione che puoi anche verificare la presenza di valori nulli e inviare DbNullable se i parametri sono nulli in quanto potresti ottenere un'eccezione come

La query con parametri "..." prevede il parametro "@parameterName", che non è stato fornito.

Qualcosa del genere mi ha aiutato

public static object GetDBNullOrValue<T>(this T val)
{
    bool isDbNull = true;
    Type t = typeof(T);

    if (Nullable.GetUnderlyingType(t) != null)
        isDbNull = EqualityComparer<T>.Default.Equals(default(T), val);
    else if (t.IsValueType)
        isDbNull = false;
    else
        isDbNull = val == null;

    return isDbNull ? DBNull.Value : (object) val;
}

(il credito per il metodo va a https://stackoverflow.com/users/284240/tim-schmelter )

Quindi usalo come:

new SqlParameter("@parameterName", parameter.GetValueOrDbNull())

oppure un'altra soluzione, più semplice, ma non generica sarebbe:

new SqlParameter("@parameterName", parameter??(object)DBNull.Value)

0

Ho ricevuto lo stesso messaggio di errore quando stavo chiamando una stored procedure che accetta due parametri di input e restituisce 3 valori utilizzando l'istruzione SELECT e ho risolto il problema come di seguito in EF Code First Approach

 SqlParameter @TableName = new SqlParameter()
        {
            ParameterName = "@TableName",
            DbType = DbType.String,
            Value = "Trans"
        };

SqlParameter @FieldName = new SqlParameter()
        {
            ParameterName = "@FieldName",
            DbType = DbType.String,
            Value = "HLTransNbr"
        };


object[] parameters = new object[] { @TableName, @FieldName };

List<Sample> x = this.Database.SqlQuery<Sample>("EXEC usp_NextNumberBOGetMulti @TableName, @FieldName", parameters).ToList();


public class Sample
{
    public string TableName { get; set; }
    public string FieldName { get; set; }
    public int NextNum { get; set; }
}

AGGIORNAMENTO : Sembra che con SQL SERVER 2005 la parola chiave EXEC mancante stia creando problemi. Quindi, per consentirgli di funzionare con tutte le versioni di SQL SERVER, ho aggiornato la mia risposta e ho aggiunto EXEC nella riga sottostante

 List<Sample> x = this.Database.SqlQuery<Sample>(" EXEC usp_NextNumberBOGetMulti @TableName, @FieldName", param).ToList();

Si prega di vedere il collegamento sotto. Non è necessario utilizzare exec msdn.microsoft.com/en-us/data/jj592907.aspx
Ziggler

0

Ho fatto il mio con EF 6.x in questo modo:

using(var db = new ProFormDbContext())
            {
                var Action = 1; 
                var xNTID = "A239333";

                var userPlan = db.Database.SqlQuery<UserPlan>(
                "AD.usp_UserPlanInfo @Action, @NTID", //, @HPID",
                new SqlParameter("Action", Action),
                new SqlParameter("NTID", xNTID)).ToList();


            }

Non raddoppiare il parametro sql, alcune persone si bruciano facendo questo sulla loro variabile

var Action = new SqlParameter("@Action", 1);  // Don't do this, as it is set below already.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.