Why does this EF insert with IDENTITY_INSERT not work?
I did not honor the tags of the question telling this is about EF6.
This answer will work for EF Core
The real culprit here is not the missing transaction, but the small inconvenience, that Database.ExectueSqlCommand()
will not keep the connection open, when not explicitly opened before.
using (var db = new AppDbContext())
{
var item = new IdentityItem {Id = 418, Name = "Abrahadabra" };
db.IdentityItems.Add(item);
db.Database.OpenConnection();
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT Test.Items ON;");
db.SaveChanges();
}
will also do, since SET IDENTITY_INSERT [...] ON/OFF
will be bound to your connection.
According to this previous Question you need to begin a transaction of your context. After saving the change you have to restate the Identity Insert column too and finally you must have to commit the transaction.
using (var db = new AppDbContext())
using (var transaction = db .Database.BeginTransaction())
{
var item = new IdentityItem {Id = 418, Name = "Abrahadabra" };
db.IdentityItems.Add(item);
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT Test.Items ON;");
db.SaveChanges();
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT Test.Items OFF");
transaction.Commit();
}
To force EF writing ID of your entity, you have to configure the ID as not store generated otherwise EF will never include the ID in the insert statement.
So, you need to change the model on the fly and configure the entity ID as you need.
The problem is that the model is cached and is quite tricky to change it on the fly (I'm quite sure I've done it but actually I can't find the code, probably I throwed it away). The shortest way is to create two different contexts where you configure your entity in two different ways, as DatabaseGeneratedOption.None
(when you need to write the ID) and as DatabaseGeneratedOption.Identity
(when you need the autonumbering ID).