private static bool IsCandidateNavigationProperty(
            InternalEntityTypeBuilder sourceEntityTypeBuilder, string navigationName, PropertyInfo propertyInfo)
        {
            if (propertyInfo == null)
            {
                return(false);
            }

            if (sourceEntityTypeBuilder == null ||
                sourceEntityTypeBuilder.ModelBuilder.IsIgnored(sourceEntityTypeBuilder.Metadata.Name, ConfigurationSource.Convention))
            {
                return(false);
            }

            if (sourceEntityTypeBuilder.IsIgnored(navigationName, ConfigurationSource.Convention))
            {
                return(false);
            }

            if (sourceEntityTypeBuilder.Metadata.FindProperty(navigationName) != null)
            {
                return(false);
            }

            if (sourceEntityTypeBuilder.Metadata.FindServiceProperty(navigationName) != null)
            {
                return(false);
            }

            return(true);
        }
        private IReadOnlyList <RelationshipCandidate> FindRelationshipCandidates(InternalEntityTypeBuilder entityTypeBuilder)
        {
            var relationshipCandidates = new Dictionary <Type, RelationshipCandidate>();
            var navigationCandidates   = GetNavigationCandidates(entityTypeBuilder.Metadata);

            foreach (var candidateTuple in navigationCandidates)
            {
                var navigationPropertyInfo = candidateTuple.Key;
                var targetClrType          = candidateTuple.Value;

                if (entityTypeBuilder.IsIgnored(navigationPropertyInfo.Name, ConfigurationSource.Convention))
                {
                    continue;
                }

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

                var entityType = entityTypeBuilder.Metadata;
                RelationshipCandidate existingCandidate;
                if (relationshipCandidates.TryGetValue(targetClrType, out existingCandidate))
                {
                    if (candidateTargetEntityTypeBuilder.Metadata != entityType ||
                        !existingCandidate.InverseProperties.Contains(navigationPropertyInfo))
                    {
                        existingCandidate.NavigationProperties.Add(navigationPropertyInfo);
                    }

                    continue;
                }

                var navigations = new HashSet <PropertyInfo> {
                    navigationPropertyInfo
                };
                var inverseCandidates           = GetNavigationCandidates(candidateTargetEntityTypeBuilder.Metadata);
                var inverseNavigationCandidates = new HashSet <PropertyInfo>();
                foreach (var inverseCandidateTuple in inverseCandidates)
                {
                    var inversePropertyInfo = inverseCandidateTuple.Key;
                    var inverseTargetType   = inverseCandidateTuple.Value;

                    if (inverseTargetType != entityType.ClrType ||
                        Equals(navigationPropertyInfo, inversePropertyInfo) ||
                        candidateTargetEntityTypeBuilder.IsIgnored(inversePropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    inverseNavigationCandidates.Add(inversePropertyInfo);
                }

                relationshipCandidates[targetClrType] =
                    new RelationshipCandidate(candidateTargetEntityTypeBuilder, navigations, inverseNavigationCandidates);
            }

            return(relationshipCandidates.Values.ToList());
        }
Beispiel #3
0
        public virtual bool Apply(
            InternalEntityTypeBuilder sourceEntityTypeBuilder,
            InternalEntityTypeBuilder targetEntityTypeBuilder,
            string navigationName)
        {
            sourceEntityTypeBuilder = sourceEntityTypeBuilder.Metadata.Builder;
            if (sourceEntityTypeBuilder == null ||
                sourceEntityTypeBuilder.ModelBuilder.IsIgnored(sourceEntityTypeBuilder.Metadata.Name, ConfigurationSource.Convention))
            {
                return(true);
            }

            if (sourceEntityTypeBuilder.IsIgnored(navigationName, ConfigurationSource.Convention))
            {
                return(true);
            }

            Apply(sourceEntityTypeBuilder);

            foreach (var derivedType in sourceEntityTypeBuilder.Metadata.GetDerivedTypes())
            {
                Apply(derivedType.Builder);
            }

            return(true);
        }
        private IReadOnlyList <RelationshipCandidate> FindRelationshipCandidates(InternalEntityTypeBuilder entityTypeBuilder)
        {
            var entityType             = entityTypeBuilder.Metadata;
            var relationshipCandidates = new Dictionary <Type, RelationshipCandidate>();

            foreach (var navigationPropertyInfo in entityType.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
            {
                var targetClrType  = FindCandidateNavigationPropertyType(navigationPropertyInfo);
                var navigationName = navigationPropertyInfo.Name;
                if (targetClrType == null ||
                    entityTypeBuilder.IsIgnored(navigationName, configurationSource: ConfigurationSource.Convention))
                {
                    continue;
                }

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

                RelationshipCandidate existingCandidate;
                if (relationshipCandidates.TryGetValue(candidateTargetEntityTypeBuilder.Metadata.ClrType, out existingCandidate))
                {
                    if (candidateTargetEntityTypeBuilder.Metadata != entityType ||
                        !existingCandidate.InverseProperties.Contains(navigationPropertyInfo))
                    {
                        existingCandidate.NavigationProperties.Add(navigationPropertyInfo);
                    }

                    continue;
                }

                var navigations = new HashSet <PropertyInfo> {
                    navigationPropertyInfo
                };
                var inverseNavigationCandidates = new HashSet <PropertyInfo>();
                foreach (var inversePropertyInfo in candidateTargetEntityTypeBuilder.Metadata.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
                {
                    var inverseTargetType = FindCandidateNavigationPropertyType(inversePropertyInfo);
                    if (inverseTargetType == null ||
                        !inverseTargetType.GetTypeInfo().IsAssignableFrom(entityType.ClrType.GetTypeInfo()) ||
                        navigationPropertyInfo == inversePropertyInfo ||
                        candidateTargetEntityTypeBuilder.IsIgnored(inversePropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    inverseNavigationCandidates.Add(inversePropertyInfo);
                }

                relationshipCandidates[candidateTargetEntityTypeBuilder.Metadata.ClrType] =
                    new RelationshipCandidate(candidateTargetEntityTypeBuilder, navigations, inverseNavigationCandidates);
            }

            return(relationshipCandidates.Values.ToList());
        }
 private static bool IsCandidateNavigationProperty(
     InternalEntityTypeBuilder sourceEntityTypeBuilder, string navigationName, MemberInfo propertyInfo)
 => propertyInfo != null &&
 sourceEntityTypeBuilder != null &&
 !sourceEntityTypeBuilder.IsIgnored(navigationName, ConfigurationSource.Convention) &&
 sourceEntityTypeBuilder.Metadata.FindProperty(navigationName) == null &&
 sourceEntityTypeBuilder.Metadata.FindServiceProperty(navigationName) == null &&
 (!sourceEntityTypeBuilder.Metadata.IsQueryType ||
  (propertyInfo as PropertyInfo)?.PropertyType.TryGetSequenceType() == null);
        private IReadOnlyList<RelationshipCandidate> FindRelationshipCandidates(InternalEntityTypeBuilder entityTypeBuilder)
        {
            var entityType = entityTypeBuilder.Metadata;
            var relationshipCandidates = new Dictionary<Type, RelationshipCandidate>();
            foreach (var navigationPropertyInfo in entityType.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
            {
                var targetClrType = FindCandidateNavigationPropertyType(navigationPropertyInfo);
                var navigationName = navigationPropertyInfo.Name;
                if (targetClrType == null
                    || entityTypeBuilder.IsIgnored(navigationName, configurationSource: ConfigurationSource.Convention))
                {
                    continue;
                }

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

                RelationshipCandidate existingCandidate;
                if (relationshipCandidates.TryGetValue(candidateTargetEntityTypeBuilder.Metadata.ClrType, out existingCandidate))
                {
                    if (candidateTargetEntityTypeBuilder.Metadata != entityType
                        || !existingCandidate.InverseProperties.Contains(navigationPropertyInfo))
                    {
                        existingCandidate.NavigationProperties.Add(navigationPropertyInfo);
                    }

                    continue;
                }

                var navigations = new HashSet<PropertyInfo> { navigationPropertyInfo };
                var inverseNavigationCandidates = new HashSet<PropertyInfo>();
                foreach (var inversePropertyInfo in candidateTargetEntityTypeBuilder.Metadata.ClrType.GetRuntimeProperties().OrderBy(p => p.Name))
                {
                    var inverseTargetType = FindCandidateNavigationPropertyType(inversePropertyInfo);
                    if (inverseTargetType == null
                        || !inverseTargetType.GetTypeInfo().IsAssignableFrom(entityType.ClrType.GetTypeInfo())
                        || navigationPropertyInfo == inversePropertyInfo
                        || candidateTargetEntityTypeBuilder.IsIgnored(inversePropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    inverseNavigationCandidates.Add(inversePropertyInfo);
                }

                relationshipCandidates[candidateTargetEntityTypeBuilder.Metadata.ClrType] =
                    new RelationshipCandidate(candidateTargetEntityTypeBuilder, navigations, inverseNavigationCandidates);
            }

            return relationshipCandidates.Values.ToList();
        }
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public virtual bool Apply(InternalEntityTypeBuilder entityTypeBuilder, string ignoredMemberName)
        {
            var navigationCandidates = GetNavigationCandidates(entityTypeBuilder);
            var candidate            = navigationCandidates.Keys.FirstOrDefault(p => p.Name == ignoredMemberName);

            if (candidate == null)
            {
                return(true);
            }

            navigationCandidates = navigationCandidates.Remove(candidate);
            SetNavigationCandidates(entityTypeBuilder, navigationCandidates);
            DiscoverRelationships(entityTypeBuilder);
            return(entityTypeBuilder.IsIgnored(ignoredMemberName, ConfigurationSource.Convention));
        }
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public virtual bool Apply(
            InternalEntityTypeBuilder sourceEntityTypeBuilder,
            InternalEntityTypeBuilder targetEntityTypeBuilder,
            string navigationName,
            PropertyInfo propertyInfo)
        {
            if (propertyInfo == null)
            {
                return(true);
            }

            sourceEntityTypeBuilder = sourceEntityTypeBuilder.Metadata.Builder;
            if (sourceEntityTypeBuilder == null ||
                sourceEntityTypeBuilder.ModelBuilder.IsIgnored(sourceEntityTypeBuilder.Metadata.Name, ConfigurationSource.Convention))
            {
                return(true);
            }

            if (sourceEntityTypeBuilder.IsIgnored(navigationName, ConfigurationSource.Convention))
            {
                return(true);
            }

            foreach (var entityType in sourceEntityTypeBuilder.Metadata.GetDerivedTypesInclusive())
            {
                if (entityType.FindNavigation(navigationName) != null)
                {
                    continue;
                }

                var entityTypeBuilder    = entityType.Builder;
                var navigationCandidates = GetNavigationCandidates(entityTypeBuilder);
                navigationCandidates = navigationCandidates.Add(propertyInfo, FindCandidateNavigationPropertyType(propertyInfo));
                SetNavigationCandidates(entityTypeBuilder, navigationCandidates);
                DiscoverRelationships(entityTypeBuilder);
            }

            return(true);
        }
        private IReadOnlyList <RelationshipCandidate> FindRelationshipCandidates(InternalEntityTypeBuilder entityTypeBuilder)
        {
            var relationshipCandidates = new Dictionary <EntityType, RelationshipCandidate>();
            var navigationCandidates   = GetNavigationCandidates(entityTypeBuilder.Metadata);

            foreach (var candidateTuple in navigationCandidates)
            {
                var navigationPropertyInfo = candidateTuple.Key;
                var targetClrType          = candidateTuple.Value;

                if (entityTypeBuilder.IsIgnored(navigationPropertyInfo.Name, ConfigurationSource.Convention))
                {
                    continue;
                }

                InternalEntityTypeBuilder candidateTargetEntityTypeBuilder = null;
                if (!entityTypeBuilder.ModelBuilder.Metadata.IsDelegatedIdentityEntityType(targetClrType))
                {
                    candidateTargetEntityTypeBuilder = entityTypeBuilder.ModelBuilder.Entity(targetClrType, ConfigurationSource.Convention);
                }
                else if (!targetClrType.GetTypeInfo().Equals(entityTypeBuilder.Metadata.ClrType.GetTypeInfo()) &&
                         !entityTypeBuilder.Metadata.IsInDefinitionPath(targetClrType))
                {
                    candidateTargetEntityTypeBuilder =
                        entityTypeBuilder.Metadata.FindNavigation(navigationPropertyInfo.Name)?.GetTargetType().Builder
                        ?? entityTypeBuilder.ModelBuilder.Metadata.FindDelegatedIdentityEntityType(
                            targetClrType, navigationPropertyInfo.Name, entityTypeBuilder.Metadata)?.Builder
                        ?? entityTypeBuilder.ModelBuilder.AddDelegatedIdentityEntity(
                            targetClrType, navigationPropertyInfo.Name, entityTypeBuilder.Metadata, ConfigurationSource.Convention);
                }

                if (candidateTargetEntityTypeBuilder == null)
                {
                    continue;
                }

                var entityType = entityTypeBuilder.Metadata;
                if (relationshipCandidates.TryGetValue(candidateTargetEntityTypeBuilder.Metadata, out RelationshipCandidate existingCandidate))
                {
                    if (candidateTargetEntityTypeBuilder.Metadata != entityType ||
                        !existingCandidate.InverseProperties.Contains(navigationPropertyInfo))
                    {
                        existingCandidate.NavigationProperties.Add(navigationPropertyInfo);
                    }

                    continue;
                }

                var navigations = new HashSet <PropertyInfo> {
                    navigationPropertyInfo
                };
                var inverseCandidates           = GetNavigationCandidates(candidateTargetEntityTypeBuilder.Metadata);
                var inverseNavigationCandidates = new HashSet <PropertyInfo>();
                foreach (var inverseCandidateTuple in inverseCandidates)
                {
                    var inversePropertyInfo = inverseCandidateTuple.Key;
                    var inverseTargetType   = inverseCandidateTuple.Value;

                    if (inverseTargetType != entityType.ClrType ||
                        navigationPropertyInfo.IsSameAs(inversePropertyInfo) ||
                        candidateTargetEntityTypeBuilder.IsIgnored(inversePropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    inverseNavigationCandidates.Add(inversePropertyInfo);
                }

                relationshipCandidates[candidateTargetEntityTypeBuilder.Metadata] =
                    new RelationshipCandidate(candidateTargetEntityTypeBuilder, navigations, inverseNavigationCandidates);
            }

            return(relationshipCandidates.Values.ToList());
        }
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public virtual InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuilder)
        {
            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));
            var entityType = entityTypeBuilder.Metadata;

            if (!entityType.HasClrType())
            {
                return(entityTypeBuilder);
            }

            var candidates = entityType.GetRuntimeProperties().Values;

            foreach (var propertyInfo in candidates)
            {
                if (entityTypeBuilder.IsIgnored(propertyInfo.Name, ConfigurationSource.Convention) ||
                    entityType.FindProperty(propertyInfo) != null ||
                    entityType.FindNavigation(propertyInfo) != null ||
                    !propertyInfo.IsCandidateProperty(publicOnly: false) ||
                    (propertyInfo.IsCandidateProperty() &&
                     _typeMappingSource.FindMapping(propertyInfo) != null))
                {
                    continue;
                }

                var factory = _parameterBindingFactories.FindFactory(propertyInfo.PropertyType, propertyInfo.Name);
                if (factory == null)
                {
                    continue;
                }

                var duplicateMap = GetDuplicateServiceProperties(entityType);
                if (duplicateMap != null &&
                    duplicateMap.TryGetValue(propertyInfo.PropertyType, out var duplicateServiceProperties))
                {
                    duplicateServiceProperties.Add(propertyInfo);

                    return(entityTypeBuilder);
                }

                var otherServicePropertySameType = entityType.GetServiceProperties()
                                                   .FirstOrDefault(p => p.ClrType == propertyInfo.PropertyType);
                if (otherServicePropertySameType != null)
                {
                    if (ConfigurationSource.Convention.Overrides(otherServicePropertySameType.GetConfigurationSource()))
                    {
                        otherServicePropertySameType.DeclaringEntityType.RemoveServiceProperty(otherServicePropertySameType.Name);
                    }

                    AddDuplicateServiceProperty(entityTypeBuilder, propertyInfo);
                    AddDuplicateServiceProperty(entityTypeBuilder, otherServicePropertySameType.GetIdentifyingMemberInfo());

                    return(entityTypeBuilder);
                }

                entityTypeBuilder.ServiceProperty(propertyInfo, ConfigurationSource.Convention)?.SetParameterBinding(
                    (ServiceParameterBinding)factory.Bind(entityType, propertyInfo.PropertyType, propertyInfo.Name),
                    ConfigurationSource.Convention);
            }

            return(entityTypeBuilder);
        }
        private IReadOnlyList <RelationshipCandidate> FindRelationshipCandidates(InternalEntityTypeBuilder entityTypeBuilder)
        {
            var relationshipCandidates = new Dictionary <EntityType, RelationshipCandidate>();
            var navigationCandidates   = GetNavigationCandidates(entityTypeBuilder.Metadata);

            foreach (var candidateTuple in navigationCandidates)
            {
                var navigationPropertyInfo = candidateTuple.Key;
                var targetClrType          = candidateTuple.Value;

                if (entityTypeBuilder.IsIgnored(navigationPropertyInfo.Name, ConfigurationSource.Convention) ||
                    (entityTypeBuilder.Metadata.IsQueryType &&
                     navigationPropertyInfo.PropertyType.TryGetSequenceType() != null))
                {
                    continue;
                }

                InternalEntityTypeBuilder candidateTargetEntityTypeBuilder = null;
                if (!entityTypeBuilder.ModelBuilder.Metadata.HasEntityTypeWithDefiningNavigation(targetClrType))
                {
                    candidateTargetEntityTypeBuilder = entityTypeBuilder.ModelBuilder.Entity(targetClrType, ConfigurationSource.Convention);
                }
                else if (!targetClrType.GetTypeInfo().Equals(entityTypeBuilder.Metadata.ClrType.GetTypeInfo()) &&
                         !entityTypeBuilder.Metadata.IsInDefinitionPath(targetClrType))
                {
                    candidateTargetEntityTypeBuilder =
                        entityTypeBuilder.Metadata.FindNavigation(navigationPropertyInfo.Name)?.GetTargetType().Builder
                        ?? entityTypeBuilder.ModelBuilder.Metadata.FindEntityType(
                            targetClrType, navigationPropertyInfo.Name, entityTypeBuilder.Metadata)?.Builder
                        ?? entityTypeBuilder.ModelBuilder.Entity(
                            targetClrType, navigationPropertyInfo.Name, entityTypeBuilder.Metadata, ConfigurationSource.Convention);
                }

                if (candidateTargetEntityTypeBuilder == null ||
                    (entityTypeBuilder.ModelBuilder.Metadata.ShouldBeOwnedType(entityTypeBuilder.Metadata.ClrType) &&
                     candidateTargetEntityTypeBuilder.Metadata == entityTypeBuilder.Metadata))
                {
                    continue;
                }

                var candidateTargetEntityType = candidateTargetEntityTypeBuilder.Metadata;
                if (candidateTargetEntityType.IsQueryType)
                {
                    continue;
                }

                if (!entityTypeBuilder.Metadata.Model.ShouldBeOwnedType(candidateTargetEntityType.ClrType))
                {
                    var ownership = candidateTargetEntityType.FindOwnership();
                    if (ownership != null &&
                        ownership.PrincipalEntityType != entityTypeBuilder.Metadata)
                    {
                        var inverseOwnership = entityTypeBuilder.Metadata.FindOwnership();
                        if (inverseOwnership == null ||
                            inverseOwnership.PrincipalEntityType != candidateTargetEntityType)
                        {
                            continue;
                        }
                    }
                }

                var entityType = entityTypeBuilder.Metadata;

                if (relationshipCandidates.TryGetValue(candidateTargetEntityType, out var existingCandidate))
                {
                    if (candidateTargetEntityType != entityType ||
                        !existingCandidate.InverseProperties.Contains(navigationPropertyInfo))
                    {
                        existingCandidate.NavigationProperties.Add(navigationPropertyInfo);
                    }

                    continue;
                }

                var navigations = new HashSet <PropertyInfo>
                {
                    navigationPropertyInfo
                };
                var inverseCandidates           = GetNavigationCandidates(candidateTargetEntityType);
                var inverseNavigationCandidates = new HashSet <PropertyInfo>();

                foreach (var inverseCandidateTuple in inverseCandidates)
                {
                    var inversePropertyInfo = inverseCandidateTuple.Key;
                    var inverseTargetType   = inverseCandidateTuple.Value;

                    if (inverseTargetType != entityType.ClrType ||
                        navigationPropertyInfo.IsSameAs(inversePropertyInfo) ||
                        candidateTargetEntityTypeBuilder.IsIgnored(inversePropertyInfo.Name, ConfigurationSource.Convention) ||
                        entityType.IsQueryType ||
                        (entityType.HasDefiningNavigation() &&
                         entityType.DefiningEntityType == candidateTargetEntityType &&
                         entityType.DefiningNavigationName != inversePropertyInfo.Name))
                    {
                        continue;
                    }

                    inverseNavigationCandidates.Add(inversePropertyInfo);
                }

                relationshipCandidates[candidateTargetEntityType] =
                    new RelationshipCandidate(candidateTargetEntityTypeBuilder, navigations, inverseNavigationCandidates);
            }

            return(relationshipCandidates.Values.ToList());
        }
        public virtual bool Apply(
            InternalEntityTypeBuilder sourceEntityTypeBuilder,
            InternalEntityTypeBuilder targetEntityTypeBuilder,
            string navigationName)
        {
            if (sourceEntityTypeBuilder.IsIgnored(navigationName, ConfigurationSource.Convention))
            {
                return true;
            }

            Apply(sourceEntityTypeBuilder);

            foreach (var derivedType in sourceEntityTypeBuilder.Metadata.GetDerivedTypes())
            {
                Apply(sourceEntityTypeBuilder.ModelBuilder.Entity(derivedType.Name, ConfigurationSource.Convention));
            }

            return true;
        }