c# - registro - Cómo obtener el siguiente valor de identidad de SQL Server
obtener ultimo id insertado sql server (5)
Necesito obtener el siguiente valor de identidad de SQL Server
.
Yo uso este código:
SELECT IDENT_CURRENT(''table_name'') + 1
Esto es correcto, pero cuando table_name
está vacío (y el siguiente valor de identidad es "1") se devuelve "2" pero el resultado es "1"
Creo que querrá buscar una forma alternativa de calcular el siguiente valor disponible (como configurar la columna para que se incremente automáticamente ).
De la documentación de IDENT_CURRENT , con respecto a las tablas vacías:
Cuando el valor de IDENT_CURRENT es NULL (porque la tabla nunca ha contenido filas o se ha truncado), la función IDENT_CURRENT devuelve el valor de inicialización.
Ni siquiera parece tan confiable, especialmente si terminas diseñando una aplicación que tiene más de una persona escribiendo en la mesa al mismo tiempo.
Tenga cuidado al usar IDENT_CURRENT para predecir el siguiente valor de identidad generado. El valor real generado puede ser diferente de IDENT_CURRENT más IDENT_INCR debido a las inserciones realizadas por otras sesiones.
En caso de que su tabla esté vacía, esta consulta funcionará perfectamente.
SELECT
CASE
WHEN (SELECT
COUNT(1)
FROM tablename) = 0 THEN 1
ELSE IDENT_CURRENT(''tablename'') + 1
END AS Current_Identity;
Sé que ya hay una respuesta, pero realmente me molesta que todas mis búsquedas en la línea de "obtener el siguiente servidor de identidad de sql" dieran con soluciones inestables (como simplemente seleccionar el valor de identidad actual y agregar 1) o "puede" ser hecho de manera confiable ".
Hay un par de maneras de hacer esto.
SQL Server> = 2012
CREATE SEQUENCE dbo.seq_FooId START WITH 1 INCREMENT BY 1
GO
CREATE TABLE dbo.Foos (
FooId int NOT NULL
DEFAULT (NEXT VALUE FOR dbo.seq_FooId)
PRIMARY KEY CLUSTERED
)
GO
// Get the next identity before an insert
DECLARE @next_id = NEXT VALUE FOR dbo.seq_FooId
SQL Server 2012 introdujo el objeto SEQUENCE
. En este caso, la secuencia se incrementará cada vez que se llame a NEXT VALUE FOR
, por lo que no debe preocuparse por la concurrencia.
SQL Server <= 2008
CREATE TABLE dbo.Foos (
FooId int NOT NULL
IDENTITY (1, 1)
PRIMARY KEY CLUSTERED
)
GO
// Get the next identity before an insert
BEGIN TRANSACTION
SELECT TOP 1 1 FROM dbo.Foos WITH (TABLOCKX, HOLDLOCK)
DECLARE @next_id int = IDENT_CURRENT(''dbo.Foos'') + IDENT_INCR(''dbo.Foos'');
DBCC CHECKIDENT(''dbo.Foos'', RESEED, @next_id)
COMMIT TRANSACTION
Probablemente querrá encapsular todo eso en un procedimiento almacenado, especialmente porque la declaración DBCC
requiere un acceso elevado y probablemente no querrá que todos tengan ese tipo de acceso.
No es tan elegante como el NEXT VALUE FOR
, pero debería ser confiable. Tenga en cuenta que obtendrá 2
para su primer valor si no hay filas en la tabla, pero si tiene la intención de usar siempre este método para obtener la siguiente identidad, puede colocar la identidad en 0
lugar de 1
(con IDENTITY (0, 1)
Si estás listo para comenzar con 1.
¿Por qué alguien querría hacer esto?
No puedo hablar por el póster de la pregunta, pero el libro ''Diseño impulsado por dominio'' y la muestra DDD ''oficial'' utilizan esta técnica (o al menos lo insinúan) como una forma de imponer que las entidades siempre tengan un identificador válido. Si su entidad tiene un identificador falso (como -1
o por default(int)
o null
) hasta que se INSERT
en la base de datos, es posible que exista un problema de persistencia.
Tiendo a estar de acuerdo con otros carteles en que esta no es la forma correcta de hacerlo, sin embargo, puede ser conveniente para ciertos casos. Varias publicaciones preguntan por qué hacen esto en absoluto, y permítanme darles un ejemplo de dónde fue conveniente para mí, y cómo y por qué.
Estoy implementando un nodo de Bitcoin. Quiero el blockchain almacenado en una base de datos SQL. Cada bloque se recibe de la red de otros nodos y mineros. Los detalles que puedes encontrar en otra parte.
Cuando recibe un bloque, contiene un encabezado, cualquier número de transacciones y cada transacción cualquier número de entradas y salidas. Tengo 4 tablas en mi base de datos, lo has adivinado, una tabla de encabezado, tabla de transacciones, tabla de entradas y tabla de salidas. Cada fila de la transacción, la tabla de entradas y salidas están vinculadas con ID para unirse a la fila del encabezado.
Algunos bloques contienen varios miles de transacciones. Algunas transacciones cientos de entradas y / o salidas. Los necesito almacenados en la base de datos desde una llamada conveniente en C # sin comprometer la integridad (todos los identificadores se vinculan) y con un rendimiento decente, que no puedo obtener al cometer fila por fila cuando hay cerca de 10000 confirmaciones.
En su lugar, me aseguro de sincronizar y bloquear el objeto de mi base de datos en C # durante la operación (y no tengo que preocuparme por otros procesos que acceden a la base de datos), así que puedo hacer un IDENT_CURRENT en las 4 tablas. los valores de un proceso almacenado, llenan las casi 10000 filas en la Lista 4 <DBTableRow> mientras se incrementan los ID y se llama el conjunto de SqlBulkCopy.WriteToServer con la opción SqlBulkCopyOptions.KeepIdentity, y luego se envía todo en 4 llamadas sencillas, una para cada conjunto de tablas .
La ganancia de rendimiento (en una computadora portátil de rango medio de 4-5 años) iba de unos 60-90 segundos a 2-3 segundos para los bloques realmente grandes, así que me alegré de conocer IDENT_CURRENT ().
La solución podría no ser elegante, podría no estar en el libro, por así decirlo, pero es conveniente y simple. También hay otras maneras de lograr esto, lo sé, pero esto fue sencillo y tomó algunas horas para implementarlo. Solo asegúrate de no tener problemas de concurrencia.
SELECT isnull(IDENT_CURRENT(''emp'') + IDENT_INCR(''emp''),1)