/// <summary> /// Find the property on the target type that acts as the back-link in the relationship /// </summary> /// <returns></returns> private static PropertyInfo FindBackLink(Resource target, Resource value, ResourceReferenceAttribute referenceAtt) { var propOnTarget = (from prop in ReferenceProperties(target.GetType(), false) where IsInstanceOfReference(prop, value) let backAtt = prop.GetCustomAttribute <ResourceReferenceAttribute>() where backAtt.Name == referenceAtt.Name && // Compare name backAtt.RelationType == referenceAtt.RelationType && // Compare relation type backAtt.Role != referenceAtt.Role // Validate inverse role select prop).FirstOrDefault(); return(propOnTarget); }
/// <summary> /// Find all resources references by the instance with the same reference information /// </summary> private static ISet <IResource> CurrentReferences(Resource instance, ResourceReferenceAttribute referenceAtt) { // Get all references of this resource with the same relation information var currentReferences = (from property in ReferenceProperties(instance.GetType(), false) let att = property.GetCustomAttribute <ResourceReferenceAttribute>() where att.RelationType == referenceAtt.RelationType && att.Name == referenceAtt.Name && att.Role == referenceAtt.Role select property.GetValue(instance)).SelectMany(ExtractAllFromProperty); return(new HashSet <IResource>(currentReferences)); }
/// <summary> /// Remove the reference to the resource on a target object /// </summary> private void ClearOnTarget(Resource target, Resource value, ResourceReferenceAttribute referenceAtt) { var prop = FindBackLink(target, value, referenceAtt); if (prop == null) { return; // No back-link -> nothing to do } // Update property ONLY if it currently points to our resource var propValue = prop.GetValue(target); if (propValue == value) { prop.SetValue(target, null); } else { (propValue as IReferenceCollection)?.UnderlyingCollection.Remove(value); } }
/// <summary> /// Update backlink if possible /// </summary> private static void SetOnTarget(Resource target, Resource value, ResourceReferenceAttribute referenceAtt) { var prop = FindBackLink(target, value, referenceAtt); if (prop == null) { return; // No back-link -> nothing to do } // Update back-link property if (prop.PropertyType.IsInstanceOfType(value)) { prop.SetValue(target, value); } else { var collection = prop.GetValue(target) as IReferenceCollection; if (collection != null && !collection.UnderlyingCollection.Contains(value)) { collection.UnderlyingCollection.Add(value); } } }
/// <summary> /// Set <see cref="ResourceRelation.SourceId"/> and <see cref="ResourceRelation.TargetId"/> depending on the <see cref="ResourceReferenceRole"/> /// of the reference property /// </summary> private static void UpdateRelationEntity(ResourceEntity resource, ResourceEntity referencedResource, ResourceRelation relEntity, ResourceReferenceAttribute att) { if (att.Role == ResourceReferenceRole.Source) { relEntity.Source = referencedResource; relEntity.Target = resource; relEntity.SourceName = att.Name; } else { relEntity.Source = resource; relEntity.Target = referencedResource; relEntity.TargetName = att.Name; } }
/// <summary> /// Create a <see cref="ResourceRelation"/> entity for a property match /// </summary> private static ResourceRelation CreateRelationForProperty(ReferenceSaverContext context, IResourceRelationRepository relationRepo, ResourceReferenceAttribute att) { var relationType = att.RelationType; var relEntity = relationRepo.Create((int)relationType); context.CreatedRelations.Add(relEntity); return(relEntity); }