Synchronization of typed models
EPiServer 7 comes with typed models for pages and blocks, this post is about what happens when we synchronize the code with the database (and not about how you define the model). All of this is documented in some way or form in the SDK and there are more areas like refactoring and renaming of properties that you can read about in the SDK that I won’t go into.
Overview of synchronization
In the first phase during startup classes marked with the [ContentType]-attribute are scanned and meta data on these classes and its properties are added to an in-memory repository, this repository contains all the information from your model classes down to individual attribute settings on properties. This phase is the only phase that deals with reflection.
In the second phase the in-memory repository is analyzed by comparing it to the content types stored in the database. From this phase the in-memory repository is updated with information about synchronization status such as if a property is new or removed and if there are any conflicts.
In the third phase any changes are committed to the database, as a general rule changes that cause loss in content on the site are never committed automatically. For example if you delete a property from code that has content stored it will be marked as “Missing in code” in admin mode and you will have to manually delete it. By enabling logging using log4net you can detect warnings or errors.
Default Values – not the ones you define in code
One of the features is that administrators can do a manual override of some settings defined in code, such as for example if a property is required or not. The “Revert to default” button in admin mode (when you are editing a property or content type) can be used to reset settings defined by an administrator.
The architecture behind this is that content types are merged with the in-memory repository when loaded from the database. And when a content type is stored back to the database it is stripped of any values that comes from the typed model. So some changes in code are actually never stored in the database at all. If you want to dig deep into the database you will notice that a lot of columns in tblPropertyDefinition, that contains defined properties, are actually NULL when the defaults comes from code.
Sort order of properties
As some of you know the sort index on property definitions has been a double-edged sword, it had this feature that it enforced unique sort orders to make it easier to get consistent sort order and to re-sort properties in the user interface.
This feature was good when page types was only entered manually and it helped the person entering the type to get correct order of things. This feature is painful when defining properties in code since the code and what is stored in the database easily gets out-of-sync if you don’t enforce unique index in code as well. So as of EPiServer 7 we have changed this behavior, sort index is never enforced when saving properties but always enforced (1..n) if you re-order using drag-n-drop or use the move up and down arrows in admin mode. To make sure the sort order is consistent we order first by index and for properties that do not have a sort index we “put them at the end” and order by the ID, so order of creation basically.
You can disable the commit phase by setting enableModelSyncCommit to false on the siteSettings-element in episerver.config. This can be useful if there are many developers working on a shared database and you want to avoid a newly added property to be removed from another piece of the code. In some scenarios it makes sense to have it disabled always in development and the dev working on the types should enabled it when needed.
A new Synchronize-button will appear in admin mode so that you can manually start the sync process on a per content item bases, it’s the exact same process as would start automatically if this setting was not disabled but on a single type. For new types you can of course create an empty page/block type and then use the Guid in the [ContentType]-attribute to hook up your code to the database.
Deployment in load balanced scenarios
Deploying code in load balanced scenarios gets a bit more trickier when your code is automatically updating the database, if you just add the latest code one server at a time with full control over when they go down and come up you are fine. But if you have a staging server and another front end server reboots while you are doing your final testing on the code using a shared database you don’t want it changing your content types with old models in the live environment.
You can solve this by disabling the commit phase on all servers but one, the staging server, as described above. You can also use our support for semantic versioning. Every time a content type is changed we make sure we update the full type name including assembly version number. If the sync process detects that for example version 1.2 was the version that updated the content type the last time and the code has version 1.1 we silently back off from that type and display a little warning message in admin to notify you. This feature can of course be used to your advantage in dev environments as well.
Another point is that the event system is not enabled until after the synchronization has completed to make sure deploying new content types on one site does not clear the caches on all other sites/servers forcing them to read potentially not up-to-date info and put unnecessary load on the database.
Note: We only check major and Minor on the version number (major.minor[.build[.revision]]).
Changing type on properties
As I mentioned in the introduction all changes that does not result in data loss for the content will be committed, including changing types on properties. But sometimes you need to change type on a property and you are fine with loosing data stored on it, so in the case of mismatch on a content type we enable the previously read-only fields Name and Type in admin mode to allow for manual override of whatever we did not dare do automatically.