/// <summary> /// Runs in the Context of a lock, and therefor can contain non thread safe calls. /// </summary> /// <param name="logicalName">Name of the logical.</param> private void SingleThreadAdd(string logicalName) { DependencyOrderLog.Enqueue("Processing entity type: " + logicalName); var info = new EntityDependencyNodeInfo(logicalName); Infos.Add(logicalName, info); if (Types.Count == 0) { DependencyOrderLog.Enqueue("No values in the list. Adding it as first."); info.Node = Types.AddFirst(info); return; } var lastDependOn = Types.LastOrDefault(t => info.DependsOn(t)); var firstDependOnCurrent = Types.FirstOrDefault(t => t.DependsOn(info)); if (lastDependOn == null) { if (firstDependOnCurrent == null) { DependencyOrderLog.Enqueue($"{logicalName} does not depend any any already processed types, and no already processed types depend on it. Adding to end."); info.Node = Types.AddLast(info); } else { DependencyOrderLog.Enqueue($"{logicalName} does not depend any any already processed types, but {firstDependOnCurrent.LogicalName} depends on it. Adding before."); info.Node = Types.AddBefore(firstDependOnCurrent.Node, info); } return; } if (!lastDependOn.DependsOn(info) && !Types.TakeWhile(t => !t.Equals(lastDependOn)).Any(t => t.DependsOn(info))) { DependencyOrderLog.Enqueue($"No type that has already been processed that occurs before the last type that {logicalName} depends on ({lastDependOn.LogicalName}), depends on the new type. Adding to end."); info.Node = Types.AddAfter(lastDependOn.Node, info); return; } DependencyOrderLog.Enqueue("Reordering Types"); var newOrder = new LinkedList <EntityDependencyNodeInfo>(); foreach (var type in Types) { // Clear IsCurrentlyCyclic foreach (var dependency in type.Dependencies.Values) { dependency.IsCurrentlyCyclic = false; } type.Node = null; } foreach (var type in Infos.Values.OrderByDescending(v => v.Dependencies.Values.Any(d => d.IsRequired)).ThenBy(v => v.LogicalName)) { PopulateNewOrder(newOrder, type); } Types = newOrder; }
/// <summary> /// Returns true if the Entity Dependency Info depends on given Entity Dependency Info. /// </summary> /// <param name="nodeInfo">The info to check to see if it is a dependency.</param> /// <returns></returns> public bool DependsOn(EntityDependencyNodeInfo nodeInfo) { //return Dependencies.Contains(info.LogicalName) || info.Dependents.Contains(LogicalName); return(Dependencies.ContainsKey(nodeInfo.LogicalName)); }
/// <summary> /// Recursively Populates the new order. /// </summary> /// <param name="newOrder">The new order.</param> /// <param name="type">The type.</param> /// <exception cref="System.ArgumentException">Cyclic dependency found.</exception> private void PopulateNewOrder(LinkedList <EntityDependencyNodeInfo> newOrder, EntityDependencyNodeInfo type) { if (newOrder.Contains(type)) { // Already visited if (type.IsCurrentlyBeingProcessed) { throw new ArgumentException("Cyclic dependency found."); } return; } type.IsCurrentlyBeingProcessed = true; foreach (var dependency in type.Dependencies. Where(d => Infos.ContainsKey(d.Key)). Select(d => new { Type = Infos[d.Key], DependentAttributes = d.Value }). OrderByDescending(d => d.Type.Dependencies.Values.Any(v => v.IsRequired)). ThenBy(d => d.Type.LogicalName)) { if (dependency.Type.IsCurrentlyBeingProcessed) { // Already Visited dependency.DependentAttributes.IsCurrentlyCyclic = true; } else { PopulateNewOrder(newOrder, dependency.Type); } } type.IsCurrentlyBeingProcessed = false; type.Node = newOrder.AddLast(type); }