Cuando usa Entity Framework, usa internamente la OUTPUT
técnica para devolver el valor de ID recién insertado
DECLARE @generated_keys table([Id] uniqueidentifier)
INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
VALUES('Malleable logarithmic casing');
SELECT t.[TurboEncabulatorID ]
FROM @generated_keys AS g
JOIN dbo.TurboEncabulators AS t
ON g.Id = t.TurboEncabulatorID
WHERE @@ROWCOUNT > 0
Los resultados de salida se almacenan en una variable de tabla temporal, se unen de nuevo a la tabla y devuelven el valor de fila de la tabla.
Nota: No tengo idea de por qué EF uniría internamente la tabla efímera a la tabla real (en qué circunstancias los dos no coincidirían).
Pero eso es lo que hace EF.
Esta técnica ( OUTPUT
) solo está disponible en SQL Server 2008 o posterior.
Editar : el motivo de la unión
La razón por la que Entity Framework se une a la tabla original, en lugar de simplemente usar los OUTPUT
valores, es porque EF también usa esta técnica para obtener la rowversion
fila recién insertada.
Puede usar la concurrencia optimista en los modelos de marco de su entidad utilizando el Timestamp
atributo: 🕗
public class TurboEncabulator
{
public String StatorSlots)
[Timestamp]
public byte[] RowVersion { get; set; }
}
Cuando haga esto, Entity Framework necesitará rowversion
la nueva fila insertada:
DECLARE @generated_keys table([Id] uniqueidentifier)
INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
VALUES('Malleable logarithmic casing');
SELECT t.[TurboEncabulatorID], t.[RowVersion]
FROM @generated_keys AS g
JOIN dbo.TurboEncabulators AS t
ON g.Id = t.TurboEncabulatorID
WHERE @@ROWCOUNT > 0
Y para recuperar esto Timetsamp
no puede usar una OUTPUT
cláusula.
Esto se debe a que si hay un disparador en la mesa, cualquier Timestamp
salida que realice estará mal:
- Inserción inicial. Marca de tiempo: 1
- La cláusula OUTPUT emite la marca de tiempo: 1
- el disparador modifica la fila. Marca de tiempo: 2
La marca de tiempo devuelta nunca será correcta si tiene un activador en la tabla. Entonces debes usar un separado SELECT
.
E incluso si estuviera dispuesto a sufrir la versión incorrecta de la fila, la otra razón para realizar una separación SELECT
es que no puede SALIR una rowversion
variable de tabla:
DECLARE @generated_keys table([Id] uniqueidentifier, [Rowversion] timestamp)
INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID, inserted.Rowversion INTO @generated_keys
VALUES('Malleable logarithmic casing');
La tercera razón para hacerlo es por simetría. Al realizar un UPDATE
sobre una mesa con un disparador, no puede usar una OUTPUT
cláusula. Intentar hacer UPDATE
con un OUTPUT
no es compatible, y dará un error:
La única forma de hacerlo es con una SELECT
declaración de seguimiento :
UPDATE TurboEncabulators
SET StatorSlots = 'Lotus-O deltoid type'
WHERE ((TurboEncabulatorID = 1) AND (RowVersion = 792))
SELECT RowVersion
FROM TurboEncabulators
WHERE @@ROWCOUNT > 0 AND TurboEncabulatorID = 1
INSERT INTO Table1(fields...) OUTPUT INSERTED.id VALUES (...)
, o un método anterior:INSERT INTO Table1(fields...) VALUES (...); SELECT SCOPE_IDENTITY();
puede obtenerlo en C # usando ExecuteScalar ().