-
Notifications
You must be signed in to change notification settings - Fork 4
Export and Import
Before any encoding begins, all entities that are needed for the export are placed in a priority queue. The order of this queue is determined by the references of the various entities. Entities that are referenced by other entities are placed earlier in the queue than the entities that reference them. Each queued item tracks all the property paths that were used to reach them. For example, if you enqueue a WorkflowType
, it will include it's WorkflowActivityTypes
which will in turn include their WorkflowActionTypes
. One of the property path's to reach those WorkflowActionTypes
would be ActivityTypes.ActionTypes
as those are the properties used to reach that entity from the root entity.
When adding something to the queue we first check for and ignore EntityType
and FieldType
entities. This are automatically generated by Rock and we should not be attempting to create them. We may, down the road, need to take special care of these types and instead of tracking them by Guid track them by full class name instead in case the Guids start to become non-consistent across installs. Secondly, if the entity to be enqueued is in the EntityPath
that is used to reach this entity then it is considered a circular reference and ignores (for example, if you enqueue an DefinedType
it will enqueue it's DefinedValues
, which will in term attempt to enqueue their referenced DefinedType
again).
Before the entity up for queue consideration is placed in the queue, we first find all referenced entities (FindReferencedEntities
) and attempt to enqueue them first. Then we add the currently considered entity to the queue, or if it is already in the queue we simply add another EntityPath
reference to it. After it is added, we consider all child entities (i.e. entities on the Many side of a Many-To-One relationship). Each of those is enqueued as well.
We use a little cheating to find referenced entities. We get all DataMember
properties of the entity and check for any of type int
or int?
whose name ends with Id
. Then we check if there is a related property on the entity with the same name, though without the Id
part (i.e. CategoryId
-> Category
). If a property is found and it is of type IEntity
then we add it to the list of potential referenced entities.
Next we give any EntityProcessor<>
implementations a chance to override that list by either adding to or removing from the list. This allows for customization of entities that do not have full foreign key references, such as AttributeValue
to have a helper method be defined to find out what that referenced entity really is.
Similarly, for finding child entities we do nearly the same thing. In this case we look for any DataMember
properties of type IEnumerable
whose base type is of type IEntity
. Any entities found in that enumerable are adding to the list of known children.
Next we check if the entity implements IHasAttributes
and if so we check for and add any Attribute
and AttributeValue
entities as children of this entity.
Again we give any EntityProcessor<>
implementations a chance to override this list. An example of this implementation can be seen with a WorkflowType
. It has Attribute
entities related to it but they do not directly reference the WorkflowType
. They use the EntityTypeQualifierColumn
and EntityTypeQualivierValue
columns to be noted as belonging to this WorkflowType
. These cannot be detected by the generic code in FindChildEntities
.
Now that we have a list of entities that need to be encoded for export we begin the easy work. The ProcessQueue
method is passed a Function that is used to determine if the various entities should be given a new Guid. Each queued entity is passed in turn to this function and flagged as wanting a new Guid. At the same time we actually encode the entity. Finally in this method we put all the encoded entities in a DataContainer
object which is returned to the caller. This is what can then be exported as JSON data.