Transacciones y @Identity

javier castagnoli
02 de Diciembre del 2010
Hola, estoy tratando de ponerme un poco con sql y las transacciones… pero me tope con un problema q la verdad todavía no entendiendo.

Lo q quiero hacer es insertar un registro con datos q pertenecen a 2 tablas diferentes:

tbEmpleados (IdEmpleado int pk, nombre varchar, idTipoEmpleado int, idCaracteristicas int)

tbCaracteristicasEmp (IdCaracteristicas int pk, edad int, colorOjos Varchar, Coloréelo varchar, altura decimal (3,2), experiencia int)

supuestamente la magia de la transacción es q ejecuta un conjunto de sentencias sql al mismo tiempo (o ejecuta todas o no ejecuta ninguna) pero a mi me tira el error de la clave foranea sobre el id de la caracteristica (detallado abajo).

Las 2 posibilidades q estoy siguiendo (aun q no las encontre) son:
- Algun error error en el Stored procedure q haga q el valor devuelto no sea el q realmente inserto… cosa q es difícil por q se ejecutaba bien la inserción de la caracteristicas y el valor q me devolvia era 1 (q estaba bien por q era el 1º registro) pero cuando va a insertar el empleado no coincide ese 1 con la caracteristica….
- Q la transacción no este funcionando y q simplemente los ejecute en linea tradicionalmente

Saludos

CODIGO:

El programa esta hecho en capas…

Capa Negocio

Private objConexion As New SqlClient.SqlConnection("Data Source=nicoSQLEXPRESS;Initial Catalog=TpCastagnoliJorgeJavier2010NuevoNuevo;Integrated Security=True")
Private objTransaction As SqlClient.SqlTransaction

Public Sub altaEmpleado(ByVal emp As CapaModelo.EmpledoModelo, ByVal empCar As CapaModelo.EmpleadoCaracteristicasModelo)
Dim empDat As New CapaDato.EmpleadoDato
Dim empCarDat As New CapaDato.EmpleadoCaracteristicasDato
'instancio la capa de datos del empleado y las caracteristicas
' la capa datos contiene el metodo para conectarse con la base de datos
Dim blnTrans As Boolean = False
Try
objConexion.Open()
objTransaction = objConexion.BeginTransaction
blnTrans = True
Dim id As Integer
' dentro de una transaccion, doy de alta la caracteristica empCar q llego como parametro
' el id de caracteristicas esta declarado como IDENTITY asi q lo tengo q recuperar, pasarselo al empleado
' y darle de alta al empleado con ese id recuperado (ver SP)
id = empCarDat.altaCaracteristica(empCar, objConexion, objTransaction)
emp.idCaracteristicas = id
empDat.AltaEmpleado(emp, objConexion, objTransaction)
'doy de alta al empleado con el id de caracteristicas ya insertado.
objTransaction.Commit()
blnTrans = False
Catch ex As Exception
If blnTrans Then
objTransaction.Rollback()
End If
Throw ex
Finally
objConexion.Close()
End Try
End Sub


Capa datos:
Empleado datos:
Public objConexion As SqlClient.SqlConnection
Public objAdapter As SqlClient.SqlDataAdapter
Public objCommand As SqlClient.SqlCommand

Public Sub AltaEmpleado(ByVal emp As CapaModelo.EmpledoModelo, ByVal objConn As SqlClient.SqlConnection, ByVal objTran As SqlClient.SqlTransaction)
Try
Dim parametros() As SqlParameter = New SqlParameter(2) {}
parametros(0) = New SqlParameter("@Nombre", SqlDbType.VarChar)
parametros(0).Value = emp.nombre
parametros(1) = New SqlParameter("@IdTipoEmpleado", SqlDbType.Int)
parametros(1).Value = emp.idTipoEmpleado
parametros(2) = New SqlParameter("@idCaracteristicas", SqlDbType.Int)
parametros(2).Value = emp.idCaracteristicas
Dim dat As New CapaDato.Datos
dat.executeNonQuery("tbEmpleados_A", parametros, objConn, objTran)
Catch ex As Exception
Throw ex
End Try
End Sub


Caracteristicas datos

Public Function altaCaracteristica(ByVal empCar As CapaModelo.EmpleadoCaracteristicasModelo, ByVal objConn As SqlClient.SqlConnection, ByVal objTran As SqlClient.SqlTransaction) As Integer
Try
Dim parametros() As SqlParameter = New SqlParameter(5) {}
parametros(0) = New SqlParameter("@Edad", SqlDbType.Int)
parametros(0).Value = empCar._Edad
parametros(1) = New SqlParameter("@ColorOjos", SqlDbType.VarChar)
parametros(1).Value = empCar._ColorOjos
parametros(2) = New SqlParameter("@colorPelo", SqlDbType.VarChar)
parametros(2).Value = empCar._colorPelo
parametros(3) = New SqlParameter("@altura", SqlDbType.Decimal)
parametros(3).Value = empCar._altura
parametros(4) = New SqlParameter("@experiencia", SqlDbType.Int)
parametros(4).Value = empCar._experiencia
parametros(5) = New SqlParameter("@id", SqlDbType.Int)
parametros(5).Direction = ParameterDirection.Output
Dim dat As New CapaDato.Datos
Dim id As Integer
id = dat.executeNonQuery("TbCaracteristicasEmp_A", parametros, objConn, objTran)
Return id
Catch ex As Exception
Throw ex
End Try
End Function


Ambos llaman al medoto:

Public Function executeNonQuery(ByVal nombreSP As String, _
ByRef params As SqlParameter(), _
ByRef unaConexion As SqlConnection, _
ByRef unaTransaction As SqlTransaction) _
As Integer
Try
objCommand = New SqlCommand
objCommand.CommandText = nombreSP
objCommand.CommandType = CommandType.StoredProcedure
objCommand.Connection = unaConexion
objCommand.Transaction = unaTransaction
For Each paramtro As SqlParameter In params
objCommand.Parameters.Add(paramtro)
Next
Dim id As Integer
id = objCommand.ExecuteNonQuery()

Return id


Catch ex As Exception
Throw ex
End Try
End Function


Stored Procedures:

Create procedure [dbo].[TbCaracteristicasEmp_A]

@Edad int,
@ColorOjos varchar(50),
@colorPelo varchar(50),
@altura decimal(3, 2),
@experiencia int,
@id int out
as
insert into TbCaracteristicasEmp (Edad ,ColorOjos ,colorPelo ,altura ,experiencia)
values (@Edad ,@ColorOjos ,@colorPelo ,@altura ,@experiencia )
SELECT @id=@@IDENTITY

-

CREATE procedure [dbo].[tbEmpleados_A]

@Nombre VarChar,
@IdTipoEmpleado int ,
@idCaracteristicas int

as

insert into tbEmpleados (Nombre, IdTipoEmpleado, idCaracteristicas)
values ( @Nombre, @IdTipoEmpleado, @idCaracteristicas)