Ejemplo n.º 1
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType == typeof(Hashtable))
            {
                var hashtable = new Hashtable();

                for (int i = 0; i < Factory.CollectionCount; i++)
                {
                    var entryKey = GetEntryKey(
                        buildContext.LogicalPropertyPath,
                        typeof(string),
                        buildContext.PropertyValueConstraints,
                        buildContext.ObjectGraphLineage);

                    //var entryKey = Factory.Create(logicalPropertyPath + "+Key", typeof(string));

                    IncrementIndex();

                    var entryValue = Factory.Create(
                        buildContext.LogicalPropertyPath + "+Value",
                        types[index],
                        buildContext.PropertyValueConstraints,
                        buildContext.ObjectGraphLineage);

                    IncrementIndex();

                    hashtable.Add(entryKey, entryValue);
                }

                return(ValueBuildResult.WithValue(hashtable, buildContext.LogicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (!buildContext.TargetType.IsValueType)
            {
                return(ValueBuildResult.NotHandled);
            }

            if (buildContext.TargetType != typeof(ushort) &&
                buildContext.TargetType != typeof(uint) &&
                buildContext.TargetType != typeof(ulong) &&
                buildContext.TargetType != typeof(byte) &&
                buildContext.TargetType != typeof(sbyte) &&
                buildContext.TargetType != typeof(short) &&
                buildContext.TargetType != typeof(int) &&
                buildContext.TargetType != typeof(long) &&
                buildContext.TargetType != typeof(decimal) &&
                buildContext.TargetType != typeof(double) &&
                buildContext.TargetType != typeof(float))
            {
                return(ValueBuildResult.NotHandled);
            }

            var value = GetRandomValue(buildContext.TargetType);

            return(ValueBuildResult.WithValue(value, buildContext.LogicalPropertyPath));
        }
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.ContainingType == null)
            {
                return(ValueBuildResult.NotHandled);
            }

            var propertyName = buildContext.LogicalPropertyPath.Split('.')
                               .Last();

            var propertyInfo = buildContext.ContainingType.GetPublicProperties()
                               .SingleOrDefault(p => p.Name == propertyName);

            if (propertyInfo == null)
            {
                throw new Exception(
                          string.Format(
                              "Property '{0}' not found on Type '{1}'.",
                              propertyName,
                              buildContext.ContainingType.FullName));
            }

            var ignoredByAttribute = Factory.CustomAttributeProvider
                                     .GetCustomAttributes(propertyInfo, true)
                                     .Any(
                a => a.GetType()
                .Name.Contains("Ignore"));

            return(ignoredByAttribute
                ? ValueBuildResult.Skip(buildContext.LogicalPropertyPath)
                : ValueBuildResult.NotHandled);
        }
Ejemplo n.º 4
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType.IsEnum)
            {
                // Initialize enum values
                if (!valuesByEnumType.ContainsKey(buildContext.TargetType))
                {
                    valuesByEnumType[buildContext.TargetType] = Enum.GetValues(buildContext.TargetType)
                                                                .Cast <int>()
                                                                .ToList();

                    valueIndicesByEnumType[buildContext.TargetType] = 0;
                }

                // Get the current index and list of enum values
                int index      = valueIndicesByEnumType[buildContext.TargetType];
                var enumValues = valuesByEnumType[buildContext.TargetType];

                // Get the next enum value
                var value = enumValues[index];

                // Increment/cycle the index for this enum type
                valueIndicesByEnumType[buildContext.TargetType] = (index + 1) % enumValues.Count;

                return(ValueBuildResult.WithValue(value, buildContext.LogicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType != typeof(IDictionary))
            {
                return(ValueBuildResult.NotHandled);
            }

            return(ValueBuildResult.WithValue(new Dictionary <string, object>(), buildContext.LogicalPropertyPath));
        }
Ejemplo n.º 6
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType == typeof(object))
            {
                var value = "Object" + nextValue++;
                return(ValueBuildResult.WithValue(value, buildContext.LogicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            string logicalPath        = buildContext.LogicalPropertyPath;
            string propertyName       = buildContext.GetPropertyName();
            var    containingInstance = buildContext.GetContainingInstance();

            int number;
            ValueBuildResult result;

            string identifierPropertyName = propertyName.Contains("USI")
                ? "USI"
                : propertyName.Contains("UniqueId")
                    ? "UniqueId"
                    : string.Empty;

            if (string.IsNullOrEmpty(identifierPropertyName))
            {
                return(ValueBuildResult.NotHandled);
            }

            var personType = Regex.Split(propertyName, identifierPropertyName)?[0];

            switch (identifierPropertyName)
            {
            case "USI":
                var alreadyAssignedUniqueId = GetPropertyValue <string>(containingInstance, personType + "UniqueId");

                if (alreadyAssignedUniqueId != null)
                {
                    return(ValueBuildResult.WithValue(int.Parse(alreadyAssignedUniqueId.Substring(1)), logicalPath));
                }

                number = _numberByPersonType.GetOrAdd(personType, x => 1);
                result = ValueBuildResult.WithValue(number, logicalPath);
                _numberByPersonType[personType] = ++number;
                return(result);

            case "UniqueId":
                var alreadyAssignedUSI = GetPropertyValue <int>(containingInstance, personType + "USI");

                if (alreadyAssignedUSI != 0)
                {
                    return(ValueBuildResult.WithValue("S" + alreadyAssignedUSI, logicalPath));
                }

                number = _numberByPersonType.GetOrAdd(personType, x => 1);
                result = ValueBuildResult.WithValue("S" + number, logicalPath);
                _numberByPersonType[personType] = ++number;
                return(result);
            }

            return(ValueBuildResult.NotHandled);
        }
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            Type   targetType          = buildContext.TargetType;
            string logicalPropertyPath = buildContext.LogicalPropertyPath;

            if (targetType == typeof(int) && logicalPropertyPath.EndsWith("EducationOrganizationId"))
            {
                var value = Ids.HighSchool;
                return(ValueBuildResult.WithValue(value, logicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
Ejemplo n.º 9
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            string propertyName = buildContext.GetPropertyName();
            string logicalPath  = buildContext.LogicalPropertyPath;

            var containingInstance = buildContext.GetContainingInstance();

            if (propertyName.EndsWith(_propertySuffix))
            {
                var descriptorValue = EdFiDescriptorReferenceSpecification.GetFullyQualifiedDescriptorReference(
                    $"uri://ed-fi.org/{propertyName}",
                    propertyName.Substring(0, 1));

                var alreadyAssignedId = GetPropertyValue <int>(containingInstance, propertyName + "Id");

                // If already assigned, build new value based on existing Id
                if (alreadyAssignedId != 0)
                {
                    return(ValueBuildResult.WithValue(descriptorValue + alreadyAssignedId, logicalPath));
                }

                string key    = ProcessPathForLeafCollectionCounterResetBehavior(logicalPath);
                int    number = _numberByTypeName.GetOrAdd(logicalPath, x => 1);
                var    result = ValueBuildResult.WithValue(descriptorValue + number++, logicalPath);
                _numberByTypeName[key] = number;
                return(result);
            }

            if (propertyName.EndsWith(_propertySuffix + "Id"))
            {
                string valuePropertyName = propertyName.TrimSuffix("Id");
                string valueLogicalPath  = logicalPath.TrimSuffix("Id");

                string alreadyAssignedValue = GetPropertyValue <string>(containingInstance, valuePropertyName);

                // If already assigned, extract Id from the value
                if (alreadyAssignedValue != null)
                {
                    return(ValueBuildResult.WithValue(Convert.ToInt32(alreadyAssignedValue.Last()), logicalPath));
                }

                string key    = ProcessPathForLeafCollectionCounterResetBehavior(valueLogicalPath);
                int    number = _numberByTypeName.GetOrAdd(key, x => 1);
                var    result = ValueBuildResult.WithValue(number++, logicalPath);
                _numberByTypeName[key] = number;
                return(result);
            }

            return(ValueBuildResult.NotHandled);
        }
Ejemplo n.º 10
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (!buildContext.TargetType.IsValueType)
            {
                return(ValueBuildResult.NotHandled);
            }

            if (buildContext.TargetType.IsGenericType &&
                buildContext.TargetType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                bool nextResultIsNull;

                // Get or initialize the flag for this nullable type
                if (!nextNullableResultByType.TryGetValue(buildContext.TargetType, out nextResultIsNull))
                {
                    nextNullableResultByType[buildContext.TargetType] = false;
                }

                // Flip the result for the next time we request an instance of this nullable type
                nextNullableResultByType[buildContext.TargetType] = !nextResultIsNull;

                // If this result should be null, do so now
                if (nextResultIsNull)
                {
                    return(ValueBuildResult.WithValue(null, buildContext.LogicalPropertyPath));
                }

                // Reassign the nullable type to the underlying target type
                buildContext.TargetType = Nullable.GetUnderlyingType(buildContext.TargetType);
            }

            if (buildContext.TargetType == typeof(ushort) ||
                buildContext.TargetType == typeof(uint) ||
                buildContext.TargetType == typeof(ulong) ||
                buildContext.TargetType == typeof(byte) ||
                buildContext.TargetType == typeof(sbyte) ||
                buildContext.TargetType == typeof(short) ||
                buildContext.TargetType == typeof(int) ||
                buildContext.TargetType == typeof(long) ||
                buildContext.TargetType == typeof(decimal) ||
                buildContext.TargetType == typeof(double) ||
                buildContext.TargetType == typeof(float)
                )
            {
                var value = GetNextValue(buildContext.TargetType);
                return(ValueBuildResult.WithValue(value, buildContext.LogicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
Ejemplo n.º 11
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            string logicalPropertyPath = buildContext.LogicalPropertyPath;

            var propertyName = logicalPropertyPath.Split('.')
                               .Last();

            if (propertyName.Equals(_propertyName) && buildContext.TargetType == typeof(T))
            {
                return(ValueBuildResult.Skip(logicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            Type parentType = buildContext.GetParentType();

            if (parentType != null)
            {
                if (parentType == buildContext.TargetType || buildContext.TargetType.IsAssignableFrom(parentType))
                {
                    return(ValueBuildResult.WithValue(
                               buildContext.GetParentInstance(),
                               buildContext.LogicalPropertyPath));
                }
            }

            return(ValueBuildResult.NotHandled);
        }
Ejemplo n.º 13
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType != typeof(string))
            {
                return(ValueBuildResult.NotHandled);
            }

            if (index == 1)
            {
                if (!GenerateEmptyStrings)
                {
                    IncrementIndex();
                }
            }

            if (index == 2)
            {
                if (!GenerateNulls)
                {
                    IncrementIndex();
                }
            }

            ValueBuildResult buildResult;

            switch (index)
            {
            case 0:
                buildResult = ValueBuildResult.WithValue("String" + ++counter, buildContext.LogicalPropertyPath);
                break;

            case 1:
                buildResult = ValueBuildResult.WithValue(string.Empty, buildContext.LogicalPropertyPath);
                break;

            case 2:
                buildResult = ValueBuildResult.WithValue(null, buildContext.LogicalPropertyPath);
                break;

            default:
                throw new Exception(string.Format("Unhandled index: {0}", index));
            }

            IncrementIndex();

            return(buildResult);
        }
Ejemplo n.º 14
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType.IsGenericTypeDefinition)
            {
                var typeArgs = buildContext.TargetType.GetGenericArguments();

                var concreteTypes = new List <Type>();

                foreach (var typeArg in typeArgs)
                {
                    var typeConstraint = typeArg.GetGenericParameterConstraints()
                                         .FirstOrDefault();

                    if (typeConstraint == null)
                    {
                        // Just use an integer... it's simple.
                        concreteTypes.Add(typeof(int));
                    }
                    else if (typeConstraint.IsAbstract)
                    {
                        // Find derived types
                        throw new Exception(
                                  string.Format(
                                      "Generic constraint on type '{0}' uses type '{1}', which is abstract and not currently supported.",
                                      buildContext.TargetType.FullName,
                                      typeConstraint.FullName));
                    }
                    else
                    {
                        concreteTypes.Add(typeConstraint);
                    }
                }

                var closedGenericType = buildContext.TargetType.MakeGenericType(concreteTypes.ToArray());

                return(ValueBuildResult.WithValue(
                           Factory.Create(
                               buildContext.LogicalPropertyPath,
                               closedGenericType,
                               buildContext.PropertyValueConstraints,
                               buildContext.ObjectGraphLineage),
                           buildContext.LogicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
Ejemplo n.º 15
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType.IsGenericType &&
                buildContext.TargetType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                // Reassign the nullable type to the underlying target type
                buildContext.TargetType = Nullable.GetUnderlyingType(buildContext.TargetType);
            }

            if (buildContext.TargetType == typeof(T))
            {
                var value = GetNextValue();
                return(ValueBuildResult.WithValue(value, buildContext.LogicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
Ejemplo n.º 16
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType.IsGenericType &&
                buildContext.TargetType.GetGenericTypeDefinition() == typeof(Nullable <>) &&
                Nullable.GetUnderlyingType(buildContext.TargetType) == typeof(Guid))
            {
                // TODO: For REST API usage, we don't want any nullable Guids to have values, but this is not desired generic behavior.
                return(ValueBuildResult.Skip(buildContext.LogicalPropertyPath));
            }

            if (buildContext.TargetType == typeof(Guid))
            {
                return(ValueBuildResult.WithValue(Guid.NewGuid(), buildContext.LogicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
Ejemplo n.º 17
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            string logicalPropertyPath = buildContext.LogicalPropertyPath;

            if (buildContext.ContainingType == null)
            {
                return(ValueBuildResult.NotHandled);
            }

            var propertyName = logicalPropertyPath.Split('.')
                               .Last();

            var property = buildContext.ContainingType.GetPublicProperties()
                           .SingleOrDefault(p => p.Name == propertyName);

            if (property == null)
            {
                throw new Exception(
                          string.Format(
                              "Unable to find property '{0}' on type '{1}'.",
                              propertyName,
                              buildContext.ContainingType.FullName));
            }

            string parentName = GetParentTypeName(property);

            // Make sure column matches typical database conventions (performance optimization)
            if (propertyName.Equals(parentName + "Id"))
            {
                // Make sure that property "Id" type is an integer before skipping it (and assuming it's an IDENTITY column, by convention)
                if (property.PropertyType == typeof(int))
                {
                    var attributes = Factory.CustomAttributeProvider.GetCustomAttributes(property, false);

                    // If the property is an auto-incrementing value, skip it
                    if (attributes.Any(x => x is AutoIncrementAttribute))
                    {
                        return(ValueBuildResult.Skip(logicalPropertyPath));
                    }
                }
            }

            return(ValueBuildResult.NotHandled);
        }
Ejemplo n.º 18
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType != typeof(string))
            {
                return(ValueBuildResult.NotHandled);
            }

            if (buildContext.ContainingType == null)
            {
                return(ValueBuildResult.NotHandled);
            }

            int desiredLength;

            if (!TryGetLength(buildContext, out desiredLength))
            {
                return(ValueBuildResult.NotHandled);
            }

            var value = BuildStringValue(desiredLength);

            string finalValue = value;

            // Generated value is too short - fill it with "x" characters
            if (value.Length < desiredLength)
            {
                var fillLength     = desiredLength - value.Length;
                var eightKb        = (int)Math.Pow(2, 10) * 8;
                var safeFillLength = Math.Min(fillLength, eightKb);
                var fill           = new string('x', safeFillLength);

                finalValue = value + fill;
            }
            else if (value.Length > desiredLength)
            {
                finalValue = value.Substring(0, desiredLength);
            }

            return(ValueBuildResult.WithValue(finalValue, buildContext.LogicalPropertyPath));
        }
Ejemplo n.º 19
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.BuildMode != BuildMode.Modify)
            {
                return(ValueBuildResult.NotHandled);
            }

            if (buildContext.ContainingType == null)
            {
                return(ValueBuildResult.NotHandled);
            }

            var propertyName = buildContext.LogicalPropertyPath.Split('.')
                               .Last();

            var propertyInfo = buildContext.ContainingType.GetPublicProperties()
                               .SingleOrDefault(x => x.Name == propertyName);

            if (propertyInfo == null)
            {
                throw new Exception(
                          string.Format(
                              "Unable to find property '{0}' on type '{1}' (or its implementations).",
                              propertyName,
                              buildContext.ContainingType));
            }

            var attributes = Factory.CustomAttributeProvider.GetCustomAttributes(propertyInfo, false);

            var attributeTypes = attributes.Select(a => a.GetType());

            if (attributeTypes.Intersect(_ignoreAttributeMarkers)
                .Any())
            {
                return(ValueBuildResult.Skip(buildContext.LogicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
Ejemplo n.º 20
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType.IsGenericType && buildContext.TargetType.GetGenericTypeDefinition() == typeof(KeyValuePair <,>))
            {
                var typeArgs = buildContext.TargetType.GetGenericArguments();
                var kvpType  = typeof(KeyValuePair <,>).MakeGenericType(typeArgs);

                var constructor = kvpType.GetConstructor(typeArgs);

                var entryKey   = Factory.Create("xyz", typeArgs[0], buildContext.PropertyValueConstraints, buildContext.ObjectGraphLineage);
                var entryValue = Factory.Create("xyz", typeArgs[1], buildContext.PropertyValueConstraints, buildContext.ObjectGraphLineage);

                var kvp = constructor.Invoke(
                    new[]
                {
                    entryKey, entryValue
                });

                return(ValueBuildResult.WithValue(kvp, buildContext.LogicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
Ejemplo n.º 21
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType.IsGenericType && buildContext.TargetType.GetGenericTypeDefinition() == typeof(IDictionary <,>))
            {
                var  typeArgs       = buildContext.TargetType.GetGenericArguments();
                Type dictionaryType = typeof(Dictionary <,>).MakeGenericType(typeArgs);
                var  dictionary     = Activator.CreateInstance(dictionaryType);
                var  addMethod      = dictionaryType.GetMethod("Add", typeArgs);

                for (int i = 0; i < Factory.CollectionCount; i++)
                {
                    var entryKey = GetEntryKey(
                        buildContext.LogicalPropertyPath,
                        typeArgs[0],
                        buildContext.PropertyValueConstraints,
                        buildContext.ObjectGraphLineage);

                    var entryValue = Factory.Create(
                        buildContext.LogicalPropertyPath + "+Value",
                        typeArgs[1],
                        buildContext.PropertyValueConstraints,
                        buildContext.ObjectGraphLineage);

                    addMethod.Invoke(
                        dictionary,
                        new[]
                    {
                        entryKey, entryValue
                    });
                }

                return(ValueBuildResult.WithValue(dictionary, buildContext.LogicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }
Ejemplo n.º 22
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            // TODO: Confirm this as obsolete behavior due to build context's TargetType now returning the underlying type
            //if (buildContext.TargetType.IsGenericType
            //    && buildContext.TargetType.GetGenericTypeDefinition() == typeof(Nullable<>))
            //{
            //    // Reassign the nullable type to the underlying target type
            //    buildContext.TargetType = Nullable.GetUnderlyingType(buildContext.TargetType);
            //}

            if (buildContext.TargetType != typeof(decimal) &&
                buildContext.TargetType != typeof(double))    // TODO: GKM - because SDK uses doubles. Not a great choice.
            {
                return(ValueBuildResult.NotHandled);
            }

            if (buildContext.ContainingType == null)
            {
                return(ValueBuildResult.NotHandled);
            }

            var propertyName = buildContext.LogicalPropertyPath.Split('.')
                               .Last();

            var propertyInfo = buildContext.ContainingType.GetPublicProperties()
                               .SingleOrDefault(p => p.Name == propertyName);

            var attribute = Factory.CustomAttributeProvider.GetCustomAttributes(propertyInfo, typeof(RangeAttribute), false)
                            .Cast <RangeAttribute>()
                            .FirstOrDefault();

            if (attribute == null)
            {
                return(ValueBuildResult.NotHandled);
            }

            var valueAsDecimal = GetNextValue(Convert.ToDecimal(attribute.Minimum), Convert.ToDecimal(attribute.Maximum));

            object valueAsObject = 0;

            if (buildContext.TargetType == typeof(double))
            {
                valueAsObject = Convert.ToDouble(valueAsDecimal);
            }
            else if (buildContext.TargetType == typeof(decimal))
            {
                valueAsObject = valueAsDecimal;
            }
            else
            {
                // This should never happen, but guard against future changes falling through.
                throw new InvalidOperationException(
                          string.Format(
                              "Type '{0}' should never have been handled by the '{1}' value builder.",
                              buildContext.TargetType.Name,
                              GetType()
                              .Name));
            }

            return(ValueBuildResult.WithValue(valueAsObject, buildContext.LogicalPropertyPath));
        }
Ejemplo n.º 23
0
        public ValueBuildResult TryBuild(BuildContext buildContext)
        {
            if (buildContext.TargetType.IsArray
                ||
                buildContext.TargetType.IsGenericType &&
                (buildContext.TargetType.GetGenericTypeDefinition() == typeof(IEnumerable <>) ||
                 buildContext.TargetType.GetGenericTypeDefinition() == typeof(IList <>) ||
                 buildContext.TargetType.GetGenericTypeDefinition() == typeof(List <>) ||
                 buildContext.TargetType.GetGenericTypeDefinition() == typeof(ICollection <>)
                ))
            {
                var itemType = buildContext.TargetType.IsArray
                    ? buildContext.TargetType.GetElementType()
                    : buildContext.TargetType.GetGenericArguments()[0];

                var listType = typeof(List <>).MakeGenericType(itemType);
                var list     = Activator.CreateInstance(listType);

                var addMethod = listType.GetMethod(
                    "Add",
                    new[]
                {
                    itemType
                });

                var distinctValues = new HashSet <object>();

                for (int i = 0; i < Factory.CollectionCount; i++)
                {
                    var newItem = Factory.Create(
                        buildContext.LogicalPropertyPath + "[" + i + "]",
                        itemType,
                        buildContext.PropertyValueConstraints,
                        buildContext.ObjectGraphLineage);

                    // Set the parent references on all API entities to avoid the GetHashCode calls
                    // made by .NET when adding them to HashSets from causing null references exceptions.
                    // Entities use their primary key values and their parent's primary key values
                    // in the GetHashCode calculation.
                    SetEntityParentBackReferencesUpTheEntireLineage(buildContext, newItem);

                    if (newItem != null)
                    {
                        distinctValues.Add(newItem);
                    }
                }

                // Enforce distinctness in values added to the lists
                // TODO: Need unit tests for enforcing distinctness
                foreach (var item in distinctValues)
                {
                    addMethod.Invoke(
                        list,
                        new[]
                    {
                        item
                    });
                }

                if (buildContext.TargetType.IsArray)
                {
                    // Convert list to an array
                    var toArrayMethod = listType.GetMethod("ToArray");
                    return(ValueBuildResult.WithValue(toArrayMethod.Invoke(list, null), buildContext.LogicalPropertyPath));
                }

                if (buildContext.TargetType.IsGenericType && buildContext.TargetType.GetGenericTypeDefinition() == typeof(ICollection <>))
                {
                    // Entity child collection concrete implementation is HashSet<>.
                    // Convert list created above to a HashSet<T> using same generic Type as list.
                    var concreteType = typeof(HashSet <>);
                    var genericType  = concreteType.MakeGenericType(itemType);
                    var instance     = Activator.CreateInstance(genericType, list);
                    return(ValueBuildResult.WithValue(instance, buildContext.LogicalPropertyPath));
                }

                return(ValueBuildResult.WithValue(list, buildContext.LogicalPropertyPath));
            }

            return(ValueBuildResult.NotHandled);
        }