private IList GetChildren(IBlueSphereEntity parent, Type childType, string childIdentifyingPropertyName, object childIdentifyingPropertyValue, Database.IConnection connection) { var tableMapping = connection.GetMapping(childType); string query = string.Format("select * from {0} where {1} = ?", childType.GetTableName(), childType.GetForeignKeyName(parent.GetType())); if (!string.IsNullOrEmpty(childIdentifyingPropertyName)) { query = query + string.Format(" AND {0} = ?", childIdentifyingPropertyName); } IList <object> queryResults; if (!string.IsNullOrEmpty(childIdentifyingPropertyName)) { queryResults = connection.Query(tableMapping, query, parent.ID, childIdentifyingPropertyValue); } else { queryResults = connection.Query(tableMapping, query, parent.ID); } // Create a typed generic list we can assign back to parent element IList genericList = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(childType)); foreach (object item in queryResults) { genericList.Add(item); } return(genericList); }
/// <summary> /// Deletes a potentially nested object graph from the appropriate tables using the /// ChildRelationship and ForeignKey attributes to guide the process /// </summary> /// <param name="entity"></param> private void DeleteRecursive(IBlueSphereEntity entity, Database.IConnection connection) { try { connection.Delete(entity); } catch (Exception ex) { throw new Exception(string.Format("Failed to delete from table {0}, entity ID {1}.", entity.GetType().GetTableName(), entity.ID), ex); } var relationshipProperties = entity.GetType().GetChildRelationProperties(); foreach (var relationshipProperty in relationshipProperties) { this.DoRecursiveTreeAction(entity, relationshipProperty, (parent, child) => { this.DeleteRecursive(child, connection); }); } }
/// <summary> /// Private non-async version of PopulateChildrenRecursiveAsync for use within a transaction /// </summary> private void PopulateChildrenRecursive(IBlueSphereEntity parent, Database.IConnection connection) { var relationshipProperties = parent.GetType().GetChildRelationProperties(); foreach (var relationshipProperty in relationshipProperties) { Type childType = relationshipProperty.GetTypeOfChildRelation(); string childIdentifyingPropertyName = relationshipProperty.GetIdentifyingPropertyNameOfChildRelation(); object childIdentifyingPropertyValue = relationshipProperty.GetIdentifyingPropertyValueOfChildRelation(); IList children = this.GetChildren(parent, childType, childIdentifyingPropertyName, childIdentifyingPropertyValue, connection); if (relationshipProperty.GetCardinalityOfChildRelation() == RelationshipCardinality.OneToOne) { Debug.Assert(children.Count == 1, string.Format("Expected one child of type {0} for parent {1} '{2}' but found {3}", childType.Name, parent.GetType().Name, parent.ID, children.Count)); relationshipProperty.SetValue(parent, children[0]); } else if (relationshipProperty.GetCardinalityOfChildRelation() == RelationshipCardinality.OneToZeroOrOne) { Debug.Assert(children.Count <= 1, string.Format("Expected zero or one child of type {0} for parent {1} '{2}' but found {3}", childType.Name, parent.GetType().Name, parent.ID, children.Count)); if (children.Count == 1) { relationshipProperty.SetValue(parent, children[0]); } } else { relationshipProperty.SetValue(parent, children); } foreach (var child in children) { this.PopulateChildrenRecursive(child as IBlueSphereEntity, connection); } } }
/// <summary> /// Performs some action (e.g. insert or delete) recursively on the hierarchical object graph using using the /// ChildRelationship and ForeignKey attributes to guide the process. Deals with the cases where child properties /// are lists or single items. /// </summary> /// <param name="entity"></param> /// <param name="relationshipProperty"></param> /// <param name="action"></param> private void DoRecursiveTreeAction(IBlueSphereEntity entity, PropertyInfo relationshipProperty, Action <IBlueSphereEntity, IBlueSphereEntity> action) { if (relationshipProperty.GetCardinalityOfChildRelation() == RelationshipCardinality.OneToOne) { //Child Property is a single Bluesphere entity IBlueSphereEntity singleChild = relationshipProperty.GetValue(entity, null) as IBlueSphereEntity; if (singleChild == null) { throw new ArgumentException(string.Format("{0} type property {1} is not a BlueSphere entity", entity.GetType().ToString(), relationshipProperty.Name)); } action.Invoke(entity, singleChild); } else if (relationshipProperty.GetCardinalityOfChildRelation() == RelationshipCardinality.OneToZeroOrOne) { //Child Property is a single Bluesphere entity but may be null var singleChild = relationshipProperty.GetValue(entity, null); if (singleChild != null) { var singleChildBlueSphereEntity = singleChild as IBlueSphereEntity; if (singleChildBlueSphereEntity == null) { throw new ArgumentException(string.Format("{0} type property {1} is not a BlueSphere entity", entity.GetType().ToString(), relationshipProperty.Name)); } action.Invoke(entity, singleChildBlueSphereEntity); } } else { // Child property is a collection of Bluesphere entities IEnumerable <IBlueSphereEntity> children = relationshipProperty.GetValue(entity, null) as IEnumerable <IBlueSphereEntity>; if (children != null) { foreach (var child in children) { action.Invoke(entity, child); } } } }
// Ensures the property on the child labelled with the foreign key attribute lines up with // the id of the parent private static void SetForeignKeyOnChild(IBlueSphereEntity parent, IBlueSphereEntity child) { PropertyInfo foreignKeyPropInfo = child.GetType().GetForeignKeyProperty(parent.GetType()); foreignKeyPropInfo.SetValue(child, parent.ID); }