After reading many posts about how to handle sequences in EF 6 (see below) I found a way that was working for me. I'm using Code First and want to include the sequence from scratch, so without using migrations (tell me if I'm getting this wrong).
Task was to get an unique and gapless incrementing extra ID for my entity Car, which is not being used as primary key.
Here is what I'm doing now:
Entity:
public class Car
{
public int Id { get; set; }
public int CarNr { get; set; }
public string Name { get; set; }
}
Context:
public class Context : DbContext
{
public Context() : base()
{
SetDefaultConfiguration();
}
public Context(string connectionString) : base(connectionString)
{
SetDefaultConfiguration();
}
public Context(DbConnection existingConnection) : base(existingConnection, true)
{
SetDefaultConfiguration();
}
public override int SaveChanges()
{
SetCarNr();
return base.SaveChanges();
}
public override Task<int> SaveChangesAsync()
{
SetCarNr();
return base.SaveChangesAsync();
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken)
{
SetCarNr();
return base.SaveChangesAsync(cancellationToken);
}
private void SetDefaultConfiguration()
{
Database.SetInitializer(new CreateSequenceInitializer());
}
public class CreateSequenceInitializer : DropCreateDatabaseIfModelChanges<Context>
{
protected override void Seed(Context context)
{
context.Database.ExecuteSqlCommand("CREATE SEQUENCE CarNrSequence AS INT START WITH 200000 NO CACHE;");
base.Seed(context);
}
}
private void SetCarNr()
{
var carsToSave = ChangeTracker.Entries().Select(e => e.Entity).OfType<Car>();
foreach (var c in carsToSave)
{
c.CarNr = GetNextSequenceValue();
}
}
public int GetNextSequenceValue()
{
var rawQuery = Database.SqlQuery<int>("SELECT NEXT VALUE FOR CarNrSequence;");
var task = rawQuery.SingleAsync();
int nextVal = task.Result;
return nextVal;
}
public DbSet<Car> Cars { get; set; }
}
So I'm using a DatabaseInitializer
to create the sequence for me and intercept the SaveChanges
to insert the extra ID queried from the DB.
Question: Is there a better way? Is this "save"? What problems do you see?
Thanks!
PS: Here are some links that helped me a lot
- https://stackoverflow.com/questions/27077461/how-to-get-next-value-of-sql-server-sequence-in-entity-framework
- https://stackoverflow.com/questions/24162895/entity-framework-6-and-sql-server-sequences
- https://stackoverflow.com/a/34894274/226278
- https://stackoverflow.com/questions/20136504/how-can-set-a-default-value-constraint-with-entity-framework-6-code-first