public virtual InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuilder)
        {
            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));
            var entityType = entityTypeBuilder.Metadata;

            var navigationPairCandidates = new Dictionary<Type, Tuple<List<PropertyInfo>, List<PropertyInfo>>>();
            if (entityType.HasClrType)
            {
                foreach (var navigationPropertyInfo in entityType.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
                {
                    var entityClrType = navigationPropertyInfo.FindCandidateNavigationPropertyType();
                    if (entityClrType == null
                        || !entityTypeBuilder.CanAddNavigation(navigationPropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    var targetEntityTypeBuilder = entityTypeBuilder.ModelBuilder.Entity(entityClrType, ConfigurationSource.Convention);
                    if (targetEntityTypeBuilder == null)
                    {
                        continue;
                    }

                    // The navigation could have been added when the target entity type was added
                    if (!entityTypeBuilder.CanAddNavigation(navigationPropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    if (navigationPairCandidates.ContainsKey(targetEntityTypeBuilder.Metadata.ClrType))
                    {
                        if (entityType != targetEntityTypeBuilder.Metadata
                            || !navigationPairCandidates[targetEntityTypeBuilder.Metadata.ClrType].Item2.Contains(navigationPropertyInfo))
                        {
                            navigationPairCandidates[targetEntityTypeBuilder.Metadata.ClrType].Item1.Add(navigationPropertyInfo);
                        }
                        continue;
                    }

                    var navigations = new List<PropertyInfo> { navigationPropertyInfo };
                    var reverseNavigations = new List<PropertyInfo>();

                    navigationPairCandidates[targetEntityTypeBuilder.Metadata.ClrType] =
                        new Tuple<List<PropertyInfo>, List<PropertyInfo>>(navigations, reverseNavigations);
                    foreach (var reversePropertyInfo in targetEntityTypeBuilder.Metadata.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
                    {
                        var reverseEntityClrType = reversePropertyInfo.FindCandidateNavigationPropertyType();
                        if (reverseEntityClrType == null
                            || !targetEntityTypeBuilder.CanAddNavigation(reversePropertyInfo.Name, ConfigurationSource.Convention)
                            || entityType.ClrType != reverseEntityClrType
                            || navigationPropertyInfo == reversePropertyInfo)
                        {
                            continue;
                        }

                        reverseNavigations.Add(reversePropertyInfo);
                    }
                }

                foreach (var navigationPairCandidate in navigationPairCandidates)
                {
                    var navigationCandidates = navigationPairCandidate.Value.Item1;
                    var reverseNavigationCandidates = navigationPairCandidate.Value.Item2;

                    if (navigationCandidates.Count > 1
                        && reverseNavigationCandidates.Count > 0)
                    {
                        // Ambiguous navigations
                        return entityTypeBuilder;
                    }

                    if (reverseNavigationCandidates.Count > 1)
                    {
                        // Ambiguous navigations
                        return entityTypeBuilder;
                    }

                    foreach (var navigationCandidate in navigationCandidates)
                    {
                        var targetEntityTypeBuilder = entityTypeBuilder.ModelBuilder.Entity(navigationCandidate.FindCandidateNavigationPropertyType(), ConfigurationSource.Convention);
                        targetEntityTypeBuilder.Relationship(entityTypeBuilder, navigationCandidate, reverseNavigationCandidates.SingleOrDefault(), ConfigurationSource.Convention);
                    }
                }
            }

            // While running conventions on entityType, its source will be DataAnnotation or higher
            // Which means that entity won't be removed while being configured even if it is unreachable
            // This takes care of removing such unreachable entities (being run after we are done building relationships using this entity)
            entityTypeBuilder.ModelBuilder.RemoveEntityTypesUnreachableByNavigations(ConfigurationSource.DataAnnotation);
            return entityTypeBuilder;
        }
        public virtual InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuilder)
        {
            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));
            var entityType = entityTypeBuilder.Metadata;

            var navigationPairCandidates = new Dictionary<InternalEntityTypeBuilder, Tuple<List<PropertyInfo>, List<PropertyInfo>>>();
            if (entityType.HasClrType)
            {
                foreach (var navigationPropertyInfo in entityType.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
                {
                    Type entityClrType;
                    if (!navigationPropertyInfo.IsCandidateNavigationProperty(out entityClrType)
                        || !entityTypeBuilder.CanAddNavigation(navigationPropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    var targetEntityTypeBuilder = entityTypeBuilder.ModelBuilder.Entity(entityClrType, ConfigurationSource.Convention);
                    if (targetEntityTypeBuilder == null)
                    {
                        continue;
                    }

                    // The navigation could have been added when the target entity type was added
                    if (!entityTypeBuilder.CanAddNavigation(navigationPropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    if (navigationPairCandidates.ContainsKey(targetEntityTypeBuilder))
                    {
                        if (entityType != targetEntityTypeBuilder.Metadata
                            || !navigationPairCandidates[targetEntityTypeBuilder].Item2.Contains(navigationPropertyInfo))
                        {
                            navigationPairCandidates[targetEntityTypeBuilder].Item1.Add(navigationPropertyInfo);
                        }
                        continue;
                    }

                    var navigations = new List<PropertyInfo> { navigationPropertyInfo };
                    var reverseNavigations = new List<PropertyInfo>();

                    navigationPairCandidates[targetEntityTypeBuilder] =
                        new Tuple<List<PropertyInfo>, List<PropertyInfo>>(navigations, reverseNavigations);
                    foreach (var reversePropertyInfo in targetEntityTypeBuilder.Metadata.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
                    {
                        Type reverseEntityClrType;
                        if (!reversePropertyInfo.IsCandidateNavigationProperty(out reverseEntityClrType)
                            || !targetEntityTypeBuilder.CanAddNavigation(reversePropertyInfo.Name, ConfigurationSource.Convention)
                            || entityType.ClrType != reverseEntityClrType
                            || navigationPropertyInfo == reversePropertyInfo)
                        {
                            continue;
                        }

                        reverseNavigations.Add(reversePropertyInfo);
                    }
                }

                foreach (var navigationPairCandidate in navigationPairCandidates)
                {
                    var targetEntityTypeBuilder = navigationPairCandidate.Key;
                    var navigationCandidates = navigationPairCandidate.Value.Item1;
                    var reverseNavigationCandidates = navigationPairCandidate.Value.Item2;

                    if (navigationCandidates.Count > 1
                        && reverseNavigationCandidates.Count > 0)
                    {
                        // Ambiguous navigations
                        return entityTypeBuilder;
                    }

                    if (reverseNavigationCandidates.Count > 1)
                    {
                        // Ambiguous navigations
                        return entityTypeBuilder;
                    }

                    foreach (var navigationCandidate in navigationCandidates)
                    {
                        TryBuildRelationship(entityTypeBuilder, targetEntityTypeBuilder, navigationCandidate, reverseNavigationCandidates.SingleOrDefault());
                    }
                }
            }

            return entityTypeBuilder;
        }
        public virtual InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuilder)
        {
            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));
            var entityType = entityTypeBuilder.Metadata;

            var navigationPairCandidates = new Dictionary <InternalEntityTypeBuilder, Tuple <List <PropertyInfo>, List <PropertyInfo> > >();

            if (entityType.HasClrType)
            {
                foreach (var navigationPropertyInfo in entityType.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
                {
                    Type entityClrType;
                    if (!navigationPropertyInfo.IsCandidateNavigationProperty(out entityClrType) ||
                        !entityTypeBuilder.CanAddNavigation(navigationPropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    var targetEntityTypeBuilder = entityTypeBuilder.ModelBuilder.Entity(entityClrType, ConfigurationSource.Convention);
                    if (targetEntityTypeBuilder == null)
                    {
                        continue;
                    }

                    // The navigation could have been added when the target entity type was added
                    if (!entityTypeBuilder.CanAddNavigation(navigationPropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    if (navigationPairCandidates.ContainsKey(targetEntityTypeBuilder))
                    {
                        if (entityType != targetEntityTypeBuilder.Metadata ||
                            !navigationPairCandidates[targetEntityTypeBuilder].Item2.Contains(navigationPropertyInfo))
                        {
                            navigationPairCandidates[targetEntityTypeBuilder].Item1.Add(navigationPropertyInfo);
                        }
                        continue;
                    }

                    var navigations = new List <PropertyInfo> {
                        navigationPropertyInfo
                    };
                    var reverseNavigations = new List <PropertyInfo>();

                    navigationPairCandidates[targetEntityTypeBuilder] =
                        new Tuple <List <PropertyInfo>, List <PropertyInfo> >(navigations, reverseNavigations);
                    foreach (var reversePropertyInfo in targetEntityTypeBuilder.Metadata.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
                    {
                        Type reverseEntityClrType;
                        if (!reversePropertyInfo.IsCandidateNavigationProperty(out reverseEntityClrType) ||
                            !targetEntityTypeBuilder.CanAddNavigation(reversePropertyInfo.Name, ConfigurationSource.Convention) ||
                            entityType.ClrType != reverseEntityClrType ||
                            navigationPropertyInfo == reversePropertyInfo)
                        {
                            continue;
                        }

                        reverseNavigations.Add(reversePropertyInfo);
                    }
                }

                foreach (var navigationPairCandidate in navigationPairCandidates)
                {
                    var targetEntityTypeBuilder     = navigationPairCandidate.Key;
                    var navigationCandidates        = navigationPairCandidate.Value.Item1;
                    var reverseNavigationCandidates = navigationPairCandidate.Value.Item2;

                    if (navigationCandidates.Count > 1 &&
                        reverseNavigationCandidates.Count > 0)
                    {
                        // Ambiguous navigations
                        return(entityTypeBuilder);
                    }

                    if (reverseNavigationCandidates.Count > 1)
                    {
                        // Ambiguous navigations
                        return(entityTypeBuilder);
                    }

                    foreach (var navigationCandidate in navigationCandidates)
                    {
                        TryBuildRelationship(entityTypeBuilder, targetEntityTypeBuilder, navigationCandidate, reverseNavigationCandidates.SingleOrDefault());
                    }
                }
            }

            return(entityTypeBuilder);
        }
Exemplo n.º 4
0
        public virtual InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuilder)
        {
            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));
            var entityType = entityTypeBuilder.Metadata;

            var navigationPairCandidates = new Dictionary <Type, Tuple <List <PropertyInfo>, List <PropertyInfo> > >();

            if (entityType.HasClrType)
            {
                foreach (var navigationPropertyInfo in entityType.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
                {
                    var entityClrType = navigationPropertyInfo.FindCandidateNavigationPropertyType();
                    if (entityClrType == null ||
                        !entityTypeBuilder.CanAddNavigation(navigationPropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    var targetEntityTypeBuilder = entityTypeBuilder.ModelBuilder.Entity(entityClrType, ConfigurationSource.Convention);
                    if (targetEntityTypeBuilder == null)
                    {
                        continue;
                    }

                    // The navigation could have been added when the target entity type was added
                    if (!entityTypeBuilder.CanAddNavigation(navigationPropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    if (navigationPairCandidates.ContainsKey(targetEntityTypeBuilder.Metadata.ClrType))
                    {
                        if (entityType != targetEntityTypeBuilder.Metadata ||
                            !navigationPairCandidates[targetEntityTypeBuilder.Metadata.ClrType].Item2.Contains(navigationPropertyInfo))
                        {
                            navigationPairCandidates[targetEntityTypeBuilder.Metadata.ClrType].Item1.Add(navigationPropertyInfo);
                        }
                        continue;
                    }

                    var navigations = new List <PropertyInfo> {
                        navigationPropertyInfo
                    };
                    var reverseNavigations = new List <PropertyInfo>();

                    navigationPairCandidates[targetEntityTypeBuilder.Metadata.ClrType] =
                        new Tuple <List <PropertyInfo>, List <PropertyInfo> >(navigations, reverseNavigations);
                    foreach (var reversePropertyInfo in targetEntityTypeBuilder.Metadata.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
                    {
                        var reverseEntityClrType = reversePropertyInfo.FindCandidateNavigationPropertyType();
                        if (reverseEntityClrType == null ||
                            !targetEntityTypeBuilder.CanAddNavigation(reversePropertyInfo.Name, ConfigurationSource.Convention) ||
                            entityType.ClrType != reverseEntityClrType ||
                            navigationPropertyInfo == reversePropertyInfo)
                        {
                            continue;
                        }

                        reverseNavigations.Add(reversePropertyInfo);
                    }
                }

                foreach (var navigationPairCandidate in navigationPairCandidates)
                {
                    var navigationCandidates        = navigationPairCandidate.Value.Item1;
                    var reverseNavigationCandidates = navigationPairCandidate.Value.Item2;

                    if (navigationCandidates.Count > 1 &&
                        reverseNavigationCandidates.Count > 0)
                    {
                        // Ambiguous navigations
                        return(entityTypeBuilder);
                    }

                    if (reverseNavigationCandidates.Count > 1)
                    {
                        // Ambiguous navigations
                        return(entityTypeBuilder);
                    }

                    foreach (var navigationCandidate in navigationCandidates)
                    {
                        var targetEntityTypeBuilder = entityTypeBuilder.ModelBuilder.Entity(navigationCandidate.FindCandidateNavigationPropertyType(), ConfigurationSource.Convention);
                        targetEntityTypeBuilder.Relationship(entityTypeBuilder, navigationCandidate, reverseNavigationCandidates.SingleOrDefault(), ConfigurationSource.Convention);
                    }
                }
            }

            // While running conventions on entityType, its source will be DataAnnotation or higher
            // Which means that entity won't be removed while being configured even if it is unreachable
            // This takes care of removing such unreachable entities (being run after we are done building relationships using this entity)
            entityTypeBuilder.ModelBuilder.RemoveEntityTypesUnreachableByNavigations(ConfigurationSource.DataAnnotation);
            return(entityTypeBuilder);
        }
Exemplo n.º 5
0
        public override InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuilder, PropertyInfo navigationPropertyInfo, InversePropertyAttribute attribute)
        {
            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));
            Check.NotNull(navigationPropertyInfo, nameof(navigationPropertyInfo));
            Check.NotNull(attribute, nameof(attribute));

            if (!entityTypeBuilder.CanAddNavigation(navigationPropertyInfo.Name, ConfigurationSource.DataAnnotation))
            {
                return(entityTypeBuilder);
            }

            var targetType = navigationPropertyInfo.FindCandidateNavigationPropertyType();
            var targetEntityTypeBuilder = entityTypeBuilder.ModelBuilder.Entity(targetType, ConfigurationSource.DataAnnotation);

            if (targetEntityTypeBuilder == null)
            {
                return(entityTypeBuilder);
            }

            // The navigation could have been added when the target entity type was added
            if (!entityTypeBuilder.CanAddNavigation(navigationPropertyInfo.Name, ConfigurationSource.DataAnnotation))
            {
                return(entityTypeBuilder);
            }

            var inverseNavigationPropertyInfo = targetType.GetRuntimeProperties().FirstOrDefault(p => string.Equals(p.Name, attribute.Property, StringComparison.OrdinalIgnoreCase));

            if (inverseNavigationPropertyInfo == null ||
                inverseNavigationPropertyInfo.FindCandidateNavigationPropertyType() != entityTypeBuilder.Metadata.ClrType)
            {
                throw new InvalidOperationException(
                          Strings.InvalidNavigationWithInverseProperty(navigationPropertyInfo.Name, entityTypeBuilder.Metadata.ClrType, attribute.Property, targetType));
            }

            if (inverseNavigationPropertyInfo == navigationPropertyInfo)
            {
                throw new InvalidOperationException(
                          Strings.SelfReferencingNavigationWithInverseProperty(
                              navigationPropertyInfo.Name,
                              entityTypeBuilder.Metadata.ClrType,
                              navigationPropertyInfo.Name,
                              entityTypeBuilder.Metadata.ClrType));
            }

            // Check for InversePropertyAttribute on the inverseNavigation to verify that it matches.
            var inverseAttribute = inverseNavigationPropertyInfo.GetCustomAttribute <InversePropertyAttribute>(true);

            if (inverseAttribute != null &&
                inverseAttribute.Property != navigationPropertyInfo.Name)
            {
                // TODO: Log error that InversePropertyAttributes are not pointing at each other
                var inverseNavigation = targetEntityTypeBuilder.Metadata.FindNavigation(inverseNavigationPropertyInfo.Name);
                if (inverseNavigation != null)
                {
                    targetEntityTypeBuilder.RemoveRelationship(inverseNavigation.ForeignKey, ConfigurationSource.DataAnnotation);
                }
                return(entityTypeBuilder);
            }

            targetEntityTypeBuilder.Relationship(entityTypeBuilder, navigationPropertyInfo, inverseNavigationPropertyInfo, ConfigurationSource.DataAnnotation);

            return(entityTypeBuilder);
        }