/// <summary> /// This method takes in a property and looks through to see if the given testProperty could be contained in it through its contained navigation properties or /// its nested contained navigation properties. /// </summary> /// <param name="odcmRootProperty">The property to start the search from</param> /// <param name="testProperty">The property to find in the from the root type</param> /// <param name="navigatedTypes">The types already navigated to prevent circular references</param> /// <param name="route">The route followed to get here</param> /// <returns></returns> private static bool IsPropertyTypeChainedContainedNavigationProperty(this OdcmProperty odcmRootProperty, OdcmProperty testProperty, HashSet <string> navigatedTypes, string route) { // check if the property already matches the type. if (odcmRootProperty.Type.FullName.Equals(testProperty.Type.FullName, StringComparison.OrdinalIgnoreCase)) { logger.Info("Property \"{0}\" matches self contained navigation property \"{1}\" of type \"{2}\"", testProperty.Name, odcmRootProperty.Name, odcmRootProperty.Type.FullName); logger.Info("Possible route from service class is: {0}{1}{1}", route, Environment.NewLine); return(true); } // check if the base class is referenced instead. if (odcmRootProperty.AsOdcmClass()?.IsAncestorOfType(testProperty.AsOdcmClass() ?? null) ?? false) { logger.Info("Property \"{0}\" of type \"{1}\" matches self contained navigation property \"{2}\" of Base type \"{3}\"", testProperty.Name, testProperty.Type.FullName, odcmRootProperty.Name, odcmRootProperty.Type.FullName); logger.Info("Possible route from service class is: {0}{1}{1}", route, Environment.NewLine); return(true); } // its not this type so lets add it to the exclusion list navigatedTypes.Add(odcmRootProperty.Type.FullName); // The current type does not match. So, we get the list of contained nav properties from the given type and recursively subject it to the same test var matchingProperty = odcmRootProperty.Type.AsOdcmClass()? .Properties .Where(prop => prop.ContainsTarget) // the nave properties with containsTarget .Where(prop => !navigatedTypes.Contains(prop.Type.FullName)) // prevent any cycle business .FirstOrDefault(prop => prop.IsPropertyTypeChainedContainedNavigationProperty(testProperty, navigatedTypes, prop.IsCollection ? $"{route}/{prop.Name}/{{id}}" : $"{route}/{prop.Name}") ); return(matchingProperty != null); }