2008-12-15 9 views
90

estoy recibiendo el error al acceder a un procedimiento almacenado en SQL ServerProcedimiento espera parámetro que no se suministró

Server Error in '/' Application. 
Procedure or function 'ColumnSeek' expects parameter '@template', which was not supplied. 

Esto sucede cuando llamo a un procedimiento almacenado con un parámetro a través de la conexión de datos de .NET para SQL (System.data.SqlClient), aunque estoy suministrando el parámetro. Aquí está mi código.

SqlConnection sqlConn = new SqlConnection(connPath); 
sqlConn.Open(); 

//METADATA RETRIEVAL 
string sqlCommString = "QCApp.dbo.ColumnSeek"; 
SqlCommand metaDataComm = new SqlCommand(sqlCommString, sqlConn); 
metaDataComm.CommandType = CommandType.StoredProcedure; 
SqlParameter sp = metaDataComm.Parameters.Add("@template",SqlDbType.VarChar,50); 
sp.Value = Template; 

SqlDataReader metadr = metaDataComm.ExecuteReader(); 

Y mi procedimiento almacenado es:

USE [QCApp] 
    GO 
    SET ANSI_NULLS ON 
    GO 
    SET QUOTED_IDENTIFIER ON 
    GO 

    ALTER PROCEDURE [dbo].[ColumnSeek] 
     @template varchar(50) 
    AS 
    EXEC('SELECT Column_Name, Data_Type 
    FROM [QCApp].[INFORMATION_SCHEMA].[COLUMNS] 
    WHERE TABLE_NAME = ' + @template); 

que estoy tratando de averiguar lo que estoy haciendo mal aquí.

Editar: Como resultado, la plantilla era nula porque me estaba poniendo su valor de un parámetro que se pasa a través de la URL y lo arruiné el parámetro url pasando (que estaba usando @ de y en lugar de &)

+0

Pregunta muy antigua, pero me encontré con el mismo problema, y ​​en mi caso, no vi que agregué un espacio extra en uno de los parámetros @. Una hora de depuración. –

+0

Consulte http://stackoverflow.com/a/26374810/1860652 para ejecutar procedimientos almacenados y obtener este error – AlexFoxGill

Respuesta

74

Revisaría el código de mi aplicación y vería a qué valor está estableciendo @template. Sospecho que es nulo y ahí radica el problema.

+28

Ah, el antiguo null vs DbNull.Value castaño ... –

+0

Sí, la plantilla era nula, me olvidé de configurarlo antes. –

+31

¿Puedo agregar que DbNull es la ÚNICA "característica" más inútil de C# – thaBadDawg

0

Primero, ¿por qué es eso un EXEC? En caso de no ser que simplemente

AS 
SELECT Column_Name, ... 
FROM ... 
WHERE TABLE_NAME = @template 

El SP actual no tiene sentido? En particular, eso buscaría una columna haciendo coincidir @template, no el valor varchar de @template. es decir, si @template es 'Column_Name', buscaría WHERE TABLE_NAME = Column_Name, lo cual es muy raro (que la tabla y la columna tengan el mismo nombre).

Además, si hacer tienen que utilizar SQL dinámico, se debe utilizar EXEC sp_ExecuteSQL (manteniendo los valores como parámetros) para evitar los ataques de inyección (en lugar de concatenación de entrada). Pero no es necesario en este caso.

Re el problema real - se ve bien de un vistazo; ¿Estás seguro de que no tienes una copia diferente del SP dando vueltas? Este es un error común ...

+0

Todavía no funciona con ese cambio. Tenía el ejecutivo porque estaba trabajando previamente con un proceso donde la cláusula from se proporcionaba desde un param así que pensé mal en este. Pero aún recibo el error con solo seleccionar –

+0

muy curioso; ¿tal vez triples para detectar errores tipográficos? –

3

Si la plantilla no está configurada (es decir, == nulo), este error se generará también.

Más comentarios:

Si conoce el valor del parámetro en el momento de agregar parámetros, también puede utilizar AddWithValue

El EXEC no es necesario. Puede hacer referencia al parámetro @template en SELECT directamente.

250

Además de las otras respuestas aquí, si se le ha olvidado poner:

cmd.CommandType = CommandType.StoredProcedure; 

Entonces usted también recibirá este error.

+6

+1 Gran respuesta. – Fenton

+0

Tuve un problema similar y esta fue la respuesta +1 – jangeador

+0

Perdí esta también. Gracias. +1 – PenFold

4

que vienen problema en todo semejante al llamar a procedimiento almacenado

CREATE PROCEDURE UserPreference_Search 
    @UserPreferencesId int, 
    @SpecialOfferMails char(1), 
    @NewsLetters char(1), 
    @UserLoginId int, 
    @Currency varchar(50) 
AS 
DECLARE @QueryString nvarchar(4000) 

SET @QueryString = 'SELECT UserPreferencesId,SpecialOfferMails,NewsLetters,UserLoginId,Currency FROM UserPreference' 
IF(@UserPreferencesId IS NOT NULL) 
BEGIN 
SET @QueryString = @QueryString + ' WHERE UserPreferencesId = @DummyUserPreferencesId'; 
END 

IF(@SpecialOfferMails IS NOT NULL) 
BEGIN 
SET @QueryString = @QueryString + ' WHERE SpecialOfferMails = @DummySpecialOfferMails'; 
END 

IF(@NewsLetters IS NOT NULL) 
BEGIN 
SET @QueryString = @QueryString + ' WHERE NewsLetters = @DummyNewsLetters'; 
END 

IF(@UserLoginId IS NOT NULL) 
BEGIN 
SET @QueryString = @QueryString + ' WHERE UserLoginId = @DummyUserLoginId'; 
END 

IF(@Currency IS NOT NULL) 
BEGIN 
SET @QueryString = @QueryString + ' WHERE Currency = @DummyCurrency'; 
END 

EXECUTE SP_EXECUTESQL @QueryString 
        ,N'@DummyUserPreferencesId int, @DummySpecialOfferMails char(1), @DummyNewsLetters char(1), @DummyUserLoginId int, @DummyCurrency varchar(50)' 
        ,@[email protected] 
        ,@[email protected] 
        ,@[email protected] 
        ,@[email protected] 
        ,@[email protected]; 

Qué dinámicamente la construcción de la consulta para la búsqueda que estaba llamando por encima de uno a:

public DataSet Search(int? AccessRightId, int? RoleId, int? ModuleId, char? CanAdd, char? CanEdit, char? CanDelete, DateTime? CreatedDatetime, DateTime? LastAccessDatetime, char? Deleted) 
    { 
     dbManager.ConnectionString = ConfigurationManager.ConnectionStrings["MSSQL"].ToString(); 
     DataSet ds = new DataSet(); 
     try 
     { 
      dbManager.Open(); 
      dbManager.CreateParameters(9); 
      dbManager.AddParameters(0, "@AccessRightId", AccessRightId, ParameterDirection.Input); 
      dbManager.AddParameters(1, "@RoleId", RoleId, ParameterDirection.Input); 
      dbManager.AddParameters(2, "@ModuleId", ModuleId, ParameterDirection.Input); 
      dbManager.AddParameters(3, "@CanAdd", CanAdd, ParameterDirection.Input); 
      dbManager.AddParameters(4, "@CanEdit", CanEdit, ParameterDirection.Input); 
      dbManager.AddParameters(5, "@CanDelete", CanDelete, ParameterDirection.Input); 
      dbManager.AddParameters(6, "@CreatedDatetime", CreatedDatetime, ParameterDirection.Input); 
      dbManager.AddParameters(7, "@LastAccessDatetime", LastAccessDatetime, ParameterDirection.Input); 
      dbManager.AddParameters(8, "@Deleted", Deleted, ParameterDirection.Input); 
      ds = dbManager.ExecuteDataSet(CommandType.StoredProcedure, "AccessRight_Search"); 
      return ds; 
     } 
     catch (Exception ex) 
     { 
     } 
     finally 
     { 
      dbManager.Dispose(); 
     } 
     return ds; 
    } 

Luego, después de mucho rascarse la cabeza he modificado almacenado procedimiento a:

ALTER PROCEDURE [dbo].[AccessRight_Search] 
    @AccessRightId int=null, 
    @RoleId int=null, 
    @ModuleId int=null, 
    @CanAdd char(1)=null, 
    @CanEdit char(1)=null, 
    @CanDelete char(1)=null, 
    @CreatedDatetime datetime=null, 
    @LastAccessDatetime datetime=null, 
    @Deleted char(1)=null 
AS 
DECLARE @QueryString nvarchar(4000) 
DECLARE @HasWhere bit 
SET @HasWhere=0 

SET @QueryString = 'SELECT a.AccessRightId, a.RoleId,a.ModuleId, a.CanAdd, a.CanEdit, a.CanDelete, a.CreatedDatetime, a.LastAccessDatetime, a.Deleted, b.RoleName, c.ModuleName FROM AccessRight a, Role b, Module c WHERE a.RoleId = b.RoleId AND a.ModuleId = c.ModuleId' 

SET @HasWhere=1; 

IF(@AccessRightId IS NOT NULL) 
    BEGIN 
     IF(@HasWhere=0) 
      BEGIN 
       SET @QueryString = @QueryString + ' WHERE a.AccessRightId = @DummyAccessRightId'; 
       SET @HasWhere=1; 
      END 
     ELSE    SET @QueryString = @QueryString + ' AND a.AccessRightId = @DummyAccessRightId'; 
    END 

IF(@RoleId IS NOT NULL) 
    BEGIN 
     IF(@HasWhere=0) 
      BEGIN 
       SET @QueryString = @QueryString + ' WHERE a.RoleId = @DummyRoleId'; 
       SET @HasWhere=1; 
      END 
     ELSE   SET @QueryString = @QueryString + ' AND a.RoleId = @DummyRoleId'; 
    END 

IF(@ModuleId IS NOT NULL) 
BEGIN 
    IF(@HasWhere=0) 
      BEGIN 
       SET @QueryString = @QueryString + ' WHERE a.ModuleId = @DummyModuleId'; 
       SET @HasWhere=1; 
      END 
    ELSE SET @QueryString = @QueryString + ' AND a.ModuleId = @DummyModuleId'; 
END 

IF(@CanAdd IS NOT NULL) 
BEGIN 
    IF(@HasWhere=0) 
      BEGIN  
       SET @QueryString = @QueryString + ' WHERE a.CanAdd = @DummyCanAdd'; 
       SET @HasWhere=1; 
      END 
    ELSE SET @QueryString = @QueryString + ' AND a.CanAdd = @DummyCanAdd'; 
END 

IF(@CanEdit IS NOT NULL) 
BEGIN 
    IF(@HasWhere=0) 
     BEGIN 
      SET @QueryString = @QueryString + ' WHERE a.CanEdit = @DummyCanEdit'; 
      SET @HasWhere=1; 
     END 
    ELSE SET @QueryString = @QueryString + ' AND a.CanEdit = @DummyCanEdit'; 
END 

IF(@CanDelete IS NOT NULL) 
BEGIN 
    IF(@HasWhere=0) 
     BEGIN 
      SET @QueryString = @QueryString + ' WHERE a.CanDelete = @DummyCanDelete'; 
      SET @HasWhere=1; 
     END 
    ELSE SET @QueryString = @QueryString + ' AND a.CanDelete = @DummyCanDelete'; 
END 

IF(@CreatedDatetime IS NOT NULL) 
BEGIN 
    IF(@HasWhere=0) 
    BEGIN 
     SET @QueryString = @QueryString + ' WHERE a.CreatedDatetime = @DummyCreatedDatetime'; 
     SET @HasWhere=1; 
    END 
    ELSE SET @QueryString = @QueryString + ' AND a.CreatedDatetime = @DummyCreatedDatetime'; 
END 

IF(@LastAccessDatetime IS NOT NULL) 
BEGIN 
    IF(@HasWhere=0) 
     BEGIN 
      SET @QueryString = @QueryString + ' WHERE a.LastAccessDatetime = @DummyLastAccessDatetime'; 
      SET @HasWhere=1; 
     END 
    ELSE SET @QueryString = @QueryString + ' AND a.LastAccessDatetime = @DummyLastAccessDatetime'; 
END 

IF(@Deleted IS NOT NULL) 
BEGIN 
    IF(@HasWhere=0) 
    BEGIN 
     SET @QueryString = @QueryString + ' WHERE a.Deleted = @DummyDeleted'; 
     SET @HasWhere=1; 
    END 
    ELSE SET @QueryString = @QueryString + ' AND a.Deleted = @DummyDeleted'; 
END 

PRINT @QueryString 

EXECUTE SP_EXECUTESQL @QueryString 
         ,N'@DummyAccessRightId int, @DummyRoleId int, @DummyModuleId int, @DummyCanAdd char(1), @DummyCanEdit char(1), @DummyCanDelete char(1), @DummyCreatedDatetime datetime, @DummyLastAccessDatetime datetime, @DummyDeleted char(1)' 
         ,@[email protected] 
         ,@[email protected] 
         ,@[email protected] 
         ,@[email protected] 
         ,@[email protected] 
         ,@[email protected] 
         ,@[email protected] 
         ,@[email protected] 
         ,@[email protected]; 

AQUÍ Estoy inicializando los parámetros de entrada de procedimiento almacenado en nulo de la siguiente manera

@AccessRightId int=null, 
@RoleId int=null, 
@ModuleId int=null, 
@CanAdd char(1)=null, 
@CanEdit char(1)=null, 
@CanDelete char(1)=null, 
@CreatedDatetime datetime=null, 
@LastAccessDatetime datetime=null, 
@Deleted char(1)=null 

que hizo el truco para mí.

Espero que esto sea útil para alguien que caiga en una trampa similar.

26

De hecho, este problema generalmente se produce al establecer un valor de parámetro nulo como HLGEM mencionado anteriormente. Pensé que elaboraría algunas soluciones a este problema que he encontrado útiles para el beneficio de personas nuevas en este problema.

La solución que yo prefiero es por defecto los parámetros de procedimiento almacenado a NULL (o cualquier valor que quiera), que fue mencionada por sangram anterior, pero se puede perder debido a que la respuesta es muy detallado. Algo a lo largo de las líneas de:

CREATE PROCEDURE GetEmployeeDetails 
    @DateOfBirth DATETIME = NULL, 
    @Surname  VARCHAR(20), 
    @GenderCode  INT = NULL, 
AS 

Esto significa que si el parámetro termina siendo fijado en código a null bajo algunas condiciones, .NET no establecerá el parámetro y el procedimiento almacenado utilizará entonces el valor por defecto que tiene definido. Otra solución, si realmente quiere resolver el problema en el código, sería el uso de un método de extensión que maneja el problema para usted, algo así como:

public static SqlParameter AddParameter<T>(this SqlParameterCollection parameters, string parameterName, T value) where T : class 
{ 
    return value == null ? parameters.AddWithValue(parameterName, DBNull.Value) : parameters.AddWithValue(parameterName, value); 
} 

Matt Hamilton tiene un buen puesto here que muestra un poco más grande métodos de extensión cuando se trata de esta área.

9

Tuve un problema en el que recibía el error cuando suministraba 0 a un parámetro entero. Y encontró que:

cmd.Parameters.AddWithValue("@Status", 0); 

obras, pero esto no es así:

cmd.Parameters.Add(new SqlParameter("@Status", 0)); 
+0

¡Gracias! Me he estado arrancando el pelo en esta toda la mañana. – colincameron

+5

La razón por la que el segundo no funciona es porque el compilador cree que está llamando a la sobrecarga * (cadena, SqlDbType) * del constructor SqlParameter. Ver comentarios [aquí] (http://msdn.microsoft.com/en-us/library/0881fz2y (v = vs.110) .aspx). – Keith

0

que tenía el mismo problema, para resolverlo sólo tiene que añadir exactamente el mismo nombre de parámetro a su colección de parámetros como en los procedimientos almacenados .

Ejemplo

Digamos que se crea un procedimiento almacenado:

create procedure up_select_employe_by_ID 
    (@ID int) 
as 
    select * 
    from employe_t 
    where employeID = @ID 

así que asegúrese de nombrar el parámetro tal como lo es en el procedimiento almacenado esto sería

cmd.parameter.add("@ID", sqltype,size).value = @ID 

si usted va

cmd.parameter.add("@employeID", sqltype,size).value = @employeid 

luego ocurre el error.

4

Para mi caso, tuve que pasar DBNULL.Value (utilizando si la condición más) a partir del código de parámetro de procedimientos almacenados que no están definidos null pero el valor es null.

0

Me encontré con este error hoy cuando los valores nulos se pasaron a los parámetros de mi procedimiento almacenado. Pude solucionarlo fácilmente alterando el procedimiento almacenado agregando valor predeterminado = nulo.

Cuestiones relacionadas