/// <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> /// 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) { var info = new EntityDependencyInfo(logicalName); Infos.Add(logicalName, info); if (Types.Count == 0 || Types.First.Value.DependsOn(info)) { // No values in the list or the first value depends on the new info value info.Node = Types.AddFirst(info); /* Check for any Types that this new type is dependent on. * Consider the Case of A -> B and B -> C * A is added first, it becomes first. C is added next, and it has no dependency on A or visa versa, so it is added last, then B is added, and it is added first, but C isn't moved * Need to move C to the front, or list discrepency */ var existingDependent = Types.Skip(1).FirstOrDefault(existingInfo => info.DependsOn(existingInfo)); if (existingDependent == null) { return; } foreach (var type in Types) { if (type == existingDependent) { // Have walked the entire list and come to the one that needs to be moved without finding anything that it depends on, free to move. Types.Remove(existingDependent); existingDependent.Node = Types.AddFirst(existingDependent); return; } if (existingDependent.Dependencies.Contains(type.LogicalName)) { Conflicts.Add(string.Format("Circular Reference Found! {0} was added, which depends on {1}, but {2} depends on {0} and was found before {1}. If {1} is needed first, add it after {0}", logicalName, existingDependent.LogicalName, type.LogicalName)); return; } } } var dependent = Types.Skip(1).FirstOrDefault(existingInfo => existingInfo.DependsOn(info)); info.Node = dependent == null?Types.AddLast(info) : Types.AddBefore(dependent.Node, info); }