Once you've enabled Configure Migrations, you'll quickly come up to the issue of Seeding.
There are a couple of issues to get around first to make it easier to know what to do in various circumstances.
AddOrUpdate extension, or custom tests.There are different forms of seeding that need to be considered:
The easiest way to handle that is something along the lines of:
var seedingType = _hostSettings.Get<SeedingType>("SeedingType");
if (seedingType >= SeedingType.ResetMutableReferenceData){
dbContext.Categories.AddOrUpdate(x=>x.Name,new Category{Name="Default"});
}
In 99% of the cases, the seeding level should always be Seeding.ResetImmutableReferenceData.
But note that at that level that ensures you always have the necessary Reference Data – but doesn't take into account any new Mutable Records needed (AppSettings stored in the db would be a good example) or Mutable Records that need changing.
That's where Patches/Updates are needed.
Another form of data change to consider is Patches/Updates that change data.
A good example might be the updating of an AppSetting value (eg: FaxServerServiceEndpoint).
The reason this is more complex is:
SeedingLevel.ResetMutableReferenceData would do this…but would always reset any changes made by SysAdmin. Annoying, therefore not appropriate. _hostSettings.Get<string>("EnvironmentIdentifier");So there are two places to consider putting it:
Each has Advantages and Disadvantages
* Advantages:
* Considerations:
SeedingLevel is changed from SeedingLevel.ResetImmutableReferenceData to SeedingLevel.ResetMutableReferenceData:EnvironmentIdentifier as well – and be kept in sync with Seeding.* Disadvantages:
//Do migration:
if ([]{"UAT","PP"...}.Contains (environmentIdentifier)){
//do an update specific to a specific environment...
}
//or don't check environmentIdentifier, and do an update specific to all environments...
* Advantages:
* Considerations:
* Disadvantages:
XAct_DataStoreUpdateLog table to keep track of what has been applied.
if (!dbLog.Contains(x=>x.Name=="FooUpdate") && (!dbLog.Contains(x.Name=="FooUpdate")&&(x.Enabled==false)){
if ([]{"UAT","PP"...}.Contains (environmentIdentifier)){
//do an update specific to a specific environment...
}
//or don't check environmentIdentifier, and do an update specific to all environments...
}
The easiest way to do seeding is to use the AddOrUpdate method:
studentCategories.AddOrUpdate(x=>x.Name, new StudentCategory("Asleep");
never test on the Id (x⇒x.Id), but a variable within the entity. If you test against the Id, and it's autoincremented, it doesn't ever work.
The downside is…AddOrUpdate is slow. Seeding used to happen only after applying a migration, but now it happens when ever you restart the app1). And by the time you've created a dozen or so reference tables…it's not fast.
In which case, consider testing whether you need to update things or not:
if (studentCategories.Count() <10){
...
...
...
}
Or you can also do
if (xactDataStoreUpdateLog.Contains(x=>x.Name=="BaseStudentCategories")){
studentCategories.AddOrUpdate(x=>x.Name,....);
}
and if you later add more:
if (xactDataStoreUpdateLog.Contains(x=>x.Name=="MoreStudentCategories")){
studentCategories.AddOrUpdate(x=>x.Name,....);
}
Instead of x queries, it's only x the first time, and then 1 the next time.