Mi inserto procedimiento almacenado:SQL Server y .NET: inserción falla (! Silencio) en el código, pero no cuando se ejecuta manualmente
ALTER procedure proj_ins_all
(
@proj_number INT,
@usr_id INT,
@download DATETIME,
@status INT
)
as
INSERT INTO project
(proj_number, usr_id, date_download, status_id)
VALUES
(@proj_number, @usr_id, @download, @status)
select SCOPE_IDENTITY()
... funciona muy bien cuando se le llama de forma manual, así:
exec proj_ins_all 9001210, 2, '2009-09-03', 2
... pero cuando se llama desde código:
_id = data.ExecuteIntScalar("proj_ins_all", arrParams);
... el inserto no sucede. Ahora, la columna de identidad se incrementa y _id establece se establece en su valor. Pero la fila en sí nunca aparece en la tabla.
La mejor conjetura que pude encontrar fue un disparador de inserción que elimina la fila recién insertada, pero no hay activadores en la tabla (¿y por qué funcionaría cuando se realiza manualmente?). Mis otros intentos estaban alrededor de una conjetura de que el procedimiento almacenado está volviendo a hacer la inserción de alguna manera, y poniendo comienzan y final y van y punto y coma en el proceso almacenado para separar correctamente el 'inserto' y el ' selección de identidad 'bits. Eso no solucionó nada.
¿Alguna idea?
Actualización:
Gracias a todos los que han ayudado hasta ahora. En la sugerencia de Preet (primera respuesta) aprendí a usar SQL Server Profiler (no puedo creer que nunca lo haya sabido antes - pensé que solo era útil para ajustar el rendimiento, no me di cuenta de que podía ver exactamente qué consulta iba a suceder) a la DB con eso).
Reveló que el SQL enviado por el método SqlCommand.ExecuteScalar() era ligeramente diferente de lo que estaba ejecutando manualmente. Estaba enviando:
exec proj_ins_all @proj_number=9001810,@usr_id=2,@download='2009-09-03 16:20:11.7130000',@status=2
Funcioné eso manualmente y listo! Un error real del servidor SQL (!):
Error al convertir el tipo de datos varchar a datetime.
Desde que estaba probando manualmente, simplemente acortado la fecha y hora de '2009-09-03 16: 20: 11.7130000' a '2009-09-03 16:20:11' y esto fijos el error; ahora la fila inserta bien.
Pero esto plantea la pregunta: ¿por qué Microsoft SQL Server no puede manejar más de 23 caracteres en ese parámetro de fecha y hora? Fue el método SqlCommand.ExecuteScalar() de Microsoft que construyó la consulta así, no yo. Este es un problema porque mi código aún no funciona.
Tan pronto como lo puse a trabajar manualmente, miré cómo configurar el parámetro SqlParameter para la fecha en el código para que envíe un valor como el que funcionó. Traté de cambiar el tipo de datos de SqlDbType.DateTime a SqlDbType.SmallDateTime. El generador de perfiles mostró que esto de hecho producía un valor de fecha más corto '2009-09-03 17:15:00', pero el inserto aún fallaba silenciosamente (el problema original).Pero cuando copié-pegué el sql del perfilador y lo intenté manualmente, funcionó. No hay error. Mismo trato al enviarlo como varchar: a la ventana de consulta SSMS le gusta, la misma consulta a través de .net falla silenciosamente.
:(
¿Alguna otra idea? Algunos configuración del tipo 'medio ambiente' en el servidor SQL como 'conjunto ANSI_NULLS off' o sea lo que sea diferente entre las conexiones a través de manuales y de código?
(Otra pregunta es ¿por qué servidor no sql me da un mensaje de error y generar una excepción cada vez que se produce este error?) código
.Net
A petición de Van, h ERE es el código .NET relevante (C# ASP.NET):
data.MakeInParam("@proj_number", SqlDbType.Int, _projNo),
data.MakeInParam("@usr_id", SqlDbType.Int, _usr.Id),
data.MakeInParam("@download", SqlDbType.SmallDateTime, _downloadDate),
data.MakeInParam("@status", SqlDbType.Int, (int)_status),
y MakeInParam tiene esta línea:
param = new SqlParameter(paramName, DbType);
Y el fichero es ejecutado como esto:
SqlCommand cmd = CreateCommand(procName, prams);
object result = cmd.ExecuteScalar();
Nota: en los parámetros anteriores, es @download ese es el problema. _downloadDate es un DateTime que se puede nulos. tenga en cuenta que el tipo sql en esta línea solía ser SqlDbType.DateTime, pero lo cambié a SqlDbType.SmallDateTime para producir una llamada que funciona manualmente (Todavía falla cuando se ejecuta desde el código).
Actualización: resuelve Gracias a Matt, por fin he encontrado y solucionado el problema: la clase de ayuda personalizada le faltaba un cmd.Transaction.Commit() en una de Sus funciones! Tenía un montón de diferentes cosas desordenadas y me perdí esto cuando revisé el código inicialmente.
Así que gracias a Matt y Preet y a todos los demás que contribuyeron.
Lecciones aprendidas
- Analizador de SQL es realmente útil. Tómese el tiempo para aprender cómo usarlo.
- Si el DB está tragando errores, o parece estar haciendo algo de acuerdo con su código, pero en realidad no aparece en el DB, verifique que la transacción se está cometiendo.
- No confíes tanto en una clase de ayudante de DB que alguien más escribió. Incluso uno que parece lo suficientemente simple al principio. Asegúrese de comprender exactamente lo que hace, ya que puede tener errores o simplemente no hacer las cosas de la manera en que cree que siempre se hacen.
* No estoy obteniendo ningún golpe en msdn para ExecuteIntScalar * Maldición, lo siento! Debería haber mencionado que es un método que alguien hizo que básicamente solo llama a ** SqlCommand.ExecuteScalar() **. ¡Perdón por la confusion! – MGOwen
Eso es todo! ¡A la clase Helper le faltaba un cmd.Transaction.Commit() en una de sus funciones! – MGOwen