/// <summary> /// Restore the property information from encodedEntity into the newly created entity. /// </summary> /// <param name="entity">The blank entity to be populated.</param> /// <param name="encodedEntity">The encoded entity data.</param> protected void RestoreEntityProperties(IEntity entity, EncodedEntity encodedEntity) { foreach (var property in GetEntityProperties(entity)) { // // If this is a plain property, just set the value. // if (encodedEntity.Properties.ContainsKey(property.Name)) { var value = encodedEntity.Properties[property.Name]; // // If this is a Guid, see if we need to remap it. // Guid?guidValue = null; if (value is Guid) { guidValue = ( Guid )value; value = FindMappedGuid(guidValue.Value); } else if (value is string) { guidValue = (( string )value).AsGuidOrNull(); if (guidValue.HasValue && guidValue.Value != FindMappedGuid(guidValue.Value)) { value = FindMappedGuid(guidValue.Value).ToString(); } } property.SetValue(entity, ChangeType(property.PropertyType, value)); } } // // Restore all references. // foreach (var reference in encodedEntity.References) { reference.Restore(entity, this); } }
/// <summary> /// Creates a new entity in the database from the encoded information. The entity /// is saved before being returned. /// </summary> /// <param name="encodedEntity">The encoded entity information to create the new entity from.</param> /// <returns>A reference to the new entity.</returns> protected IEntity CreateNewEntity(EncodedEntity encodedEntity) { Type entityType = Reflection.FindType(typeof(IEntity), encodedEntity.EntityType); var service = Reflection.GetServiceForEntityType(entityType, RockContext); if (service != null) { var addMethod = service.GetType().GetMethod("Add", new Type[] { entityType }); if (addMethod != null) { IEntity entity = ( IEntity )Activator.CreateInstance(entityType); RestoreEntityProperties(entity, encodedEntity); entity.Guid = FindMappedGuid(encodedEntity.Guid); // // Do custom pre-save processing. // foreach (var processor in FindEntityProcessors(entityType)) { processor.ProcessImportedEntity(entity, encodedEntity, encodedEntity.GetTransformData(processor.Identifier.ToString()), this); } // // Special handling of AttributeQualifier because Guids may not be the same // across installations and the AttributeId+Key columns make up a unique key. // if (encodedEntity.EntityType == "Rock.Model.AttributeQualifier") { var reference = encodedEntity.References.Where(r => r.Property == "AttributeId").First(); var attribute = GetExistingEntity("Rock.Model.Attribute", FindMappedGuid(new Guid(( string )reference.Data))); string key = ( string )encodedEntity.Properties["Key"]; var existingEntity = new AttributeQualifierService(RockContext) .GetByAttributeId(attribute.Id) .Where(a => a.Key == key) .FirstOrDefault(); if (existingEntity != null) { if (entity.Guid != encodedEntity.Guid) { throw new Exception("AttributeQualifier marked for new Guid but conflicting value already exists."); } GuidMap.AddOrReplace(encodedEntity.Guid, existingEntity.Guid); return(existingEntity); } } // // Special handling of Attribute's. The guid's might be different but if the entity type, // entity qualifiers and key are the same, assume it's the same. // else if (encodedEntity.EntityType == "Rock.Model.Attribute") { var attribute = (Rock.Model.Attribute)entity; var existingEntity = new AttributeService(RockContext) .GetByEntityTypeId(attribute.EntityTypeId) .Where(a => a.EntityTypeQualifierColumn == attribute.EntityTypeQualifierColumn && a.EntityTypeQualifierValue == attribute.EntityTypeQualifierValue && a.Key == attribute.Key) .FirstOrDefault(); if (existingEntity != null) { if (entity.Guid != encodedEntity.Guid) { throw new Exception("Attribute marked for new Guid but conflicting value already exists."); } GuidMap.AddOrReplace(encodedEntity.Guid, existingEntity.Guid); return(existingEntity); } } // // Special handling of AttributeValue's. The guid's might be different but if the attribute Id // and entity Id are the same, assume it's the same. // else if (encodedEntity.EntityType == "Rock.Model.AttributeValue") { var attributeReference = encodedEntity.References.Where(r => r.Property == "AttributeId").First(); var attribute = GetExistingEntity("Rock.Model.Attribute", FindMappedGuid(new Guid(( string )attributeReference.Data))); var entityReference = encodedEntity.References.Where(r => r.Property == "EntityId").First(); var entityRef = GetExistingEntity(entityReference.EntityType, FindMappedGuid(new Guid(( string )entityReference.Data))); var existingEntity = new AttributeValueService(RockContext) .Queryable().Where(a => a.AttributeId == attribute.Id && a.EntityId == entityRef.Id) .FirstOrDefault(); if (existingEntity != null) { if (entity.Guid != encodedEntity.Guid) { throw new Exception("AttributeValue marked for new Guid but conflicting value already exists."); } GuidMap.AddOrReplace(encodedEntity.Guid, existingEntity.Guid); return(existingEntity); } } addMethod.Invoke(service, new object[] { entity }); RockContext.SaveChanges(true); return(entity); } } throw new Exception(string.Format("Failed to create new database entity for {0}_{1}", encodedEntity.EntityType, encodedEntity.Guid)); }
/// <summary> /// Export the given entity into an EncodedEntity object. This can be used later to /// reconstruct the entity. /// </summary> /// <param name="entity">The entity to be exported.</param> /// <returns>The exported data that can be imported.</returns> protected EncodedEntity Export(QueuedEntity queuedEntity) { EncodedEntity encodedEntity = new EncodedEntity(); Type entityType = GetEntityType(queuedEntity.Entity); encodedEntity.Guid = queuedEntity.Entity.Guid; encodedEntity.EntityType = entityType.FullName; // // Generate the standard properties and references. // foreach (var property in GetEntityProperties(queuedEntity.Entity)) { // // Don't encode IEntity properties, we should have the Id encoded instead. // if (typeof(IEntity).IsAssignableFrom(property.PropertyType)) { continue; } // // Don't encode IEnumerable properties. Those should be included as // their own entities to be encoded later. // if (property.PropertyType.GetInterface("IEnumerable") != null && property.PropertyType.GetGenericArguments().Length == 1 && typeof(IEntity).IsAssignableFrom(property.PropertyType.GetGenericArguments()[0])) { continue; } encodedEntity.Properties.Add(property.Name, property.GetValue(queuedEntity.Entity)); } // // Run any post-process transforms. // foreach (var processor in FindEntityProcessors(entityType)) { var data = processor.ProcessExportedEntity(queuedEntity.Entity, encodedEntity, this); if (data != null) { encodedEntity.AddTransformData(processor.Identifier.ToString(), data); } } // // Generate the references to other entities. // foreach (var x in queuedEntity.ReferencedEntities) { encodedEntity.MakePropertyIntoReference(x.Key, x.Value); } // // Add in the user references. // encodedEntity.References.AddRange(queuedEntity.UserReferences.Values); return(encodedEntity); }
/// <summary> /// An entity has been exported and can now have any post-processing done to it /// that is needed. For example a processor might remove some properties that shouldn't /// actually have been exported. /// </summary> /// <param name="entity">The source entity that was exported.</param> /// <param name="encodedEntity">The exported data from the entity.</param> /// <param name="helper">The helper that is doing the exporting.</param> /// <returns>An object that will be encoded with the entity and passed to the ProcessImportEntity method later, or null.</returns> public object ProcessExportedEntity(IEntity entity, EncodedEntity encodedEntity, EntityCoder helper) { return(ProcessExportedEntity(( T )entity, encodedEntity, helper)); }
/// <summary> /// This method is called before the entity is saved and allows any final changes to the /// entity before it is stored in the database. Any Guid references that are not standard /// properties must also be updated, such as the Actions string of a WorkflowActionForm. /// </summary> /// <param name="entity">The in-memory entity that is about to be saved.</param> /// <param name="encodedEntity">The encoded information that was used to reconstruct the entity.</param> /// <param name="data">Custom data that was previously returned by ProcessExportedEntity.</param> /// <param name="helper">The helper in charge of the import process.</param> protected virtual void ProcessImportedEntity(T entity, EncodedEntity encodedEntity, object data, EntityDecoder helper) { }
/// <summary> /// This method is called before the entity is saved and allows any final changes to the /// entity before it is stored in the database. Any Guid references that are not standard /// properties must also be updated, such as the Actions string of a WorkflowActionForm. /// </summary> /// <param name="entity">The in-memory entity that is about to be saved.</param> /// <param name="encodedEntity">The encoded information that was used to reconstruct the entity.</param> /// <param name="data">Custom data that was previously returned by ProcessExportedEntity.</param> /// <param name="helper">The helper in charge of the import process.</param> public void ProcessImportedEntity(IEntity entity, EncodedEntity encodedEntity, object data, EntityDecoder helper) { ProcessImportedEntity(( T )entity, encodedEntity, data, helper); }
/// <summary> /// An entity has been exported and can now have any post-processing done to it /// that is needed. For example a processor might remove some properties that shouldn't /// actually have been exported. /// </summary> /// <param name="entity">The source entity that was exported.</param> /// <param name="encodedEntity">The exported data from the entity.</param> /// <param name="helper">The helper that is doing the exporting.</param> /// <returns>An object that will be encoded with the entity and passed to the ProcessImportEntity method later, or null.</returns> protected virtual object ProcessExportedEntity(T entity, EncodedEntity encodedEntity, EntityCoder helper) { return(null); }