The code below works but does not prevent a different user from inserting a row and thus creating a duplicate ID.
The IDs for the table being updated are auto incremented and assigned. In the code below I do the following:
Get the next available ID (nextID)
Set the ID of each entity to nextID++
Bulk insert
How do I lock the table such that another user cannot insert while the the three tasks above are running? I have seen similar questions that propose setting ISOLATIONLEVEL READCOMMITTED
however I don't think that will lock the table at the time I am getting the nextID.
public void BulkInsertEntities(List<Entity> entities)
{
if (entities == null)
throw new ArgumentNullException(nameof(entities));
string tableName = "Entities";
// -----------------------------------------------------------------
// Prevent other users from inserting (but not reading) here
// -----------------------------------------------------------------
long lastID = GetLastID(tableName);
entities.ForEach(x => x.ID = lastID++);
using (SqlConnection con = new SqlConnection(db.Database.GetDbConnection().ConnectionString))
{
con.Open();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(con.ConnectionString, SqlBulkCopyOptions.KeepIdentity))
{
bulkCopy.DestinationTableName = tableName;
DataTable tbl = DataUtil.ToDataTable<Entity>(entities);
foreach (DataColumn col in tbl.Columns)
bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
bulkCopy.WriteToServer(tbl);
}
}
// ---------------------------
// Allow other users to insert
// ---------------------------
}
protected long GetLastID(string tableName)
{
long lastID = 0;
using (var command = db.Database.GetDbConnection().CreateCommand())
{
command.CommandText = $"SELECT IDENT_CURRENT('{tableName}') + IDENT_INCR('{tableName}')";
db.Database.OpenConnection();
lastID = Convert.ToInt64(command.ExecuteScalar());
}
return lastID;
}