Esempio n. 1
0
        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 ||
                        navigationPropertyInfo == inversePropertyInfo ||
                        candidateTargetEntityTypeBuilder.IsIgnored(inversePropertyInfo.Name, ConfigurationSource.Convention))
                    {
                        continue;
                    }

                    inverseNavigationCandidates.Add(inversePropertyInfo);
                }

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

            return(relationshipCandidates.Values.ToList());
        }
        private void RemoveInheritedInverseNavigations(
            RelationshipCandidate relationshipCandidate,
            List <RelationshipCandidate> relationshipCandidatesHierarchy,
            HashSet <RelationshipCandidate> filteredRelationshipCandidates)
        {
            if (filteredRelationshipCandidates.Contains(relationshipCandidate) ||
                ((relationshipCandidate.NavigationProperties.Count > 1) &&
                 (relationshipCandidate.InverseProperties.Count > 0)) ||
                (relationshipCandidate.InverseProperties.Count > 1))
            {
                return;
            }

            filteredRelationshipCandidates.Add(relationshipCandidate);
            var inverseCandidate = relationshipCandidate.InverseProperties.FirstOrDefault();

            if (inverseCandidate != null)
            {
                var relationshipsToDerivedTypes = relationshipCandidatesHierarchy
                                                  .Where(r => (r.TargetTypeBuilder != relationshipCandidate.TargetTypeBuilder) &&
                                                         relationshipCandidate.TargetTypeBuilder.Metadata.IsAssignableFrom(r.TargetTypeBuilder.Metadata));
                foreach (var relationshipToDerivedType in relationshipsToDerivedTypes)
                {
                    relationshipToDerivedType.InverseProperties.RemoveWhere(i => i.Name == inverseCandidate.Name);

                    if (!filteredRelationshipCandidates.Contains(relationshipToDerivedType))
                    {
                        // An ambiguity might have been resolved
                        RemoveInheritedInverseNavigations(relationshipToDerivedType, relationshipCandidatesHierarchy, filteredRelationshipCandidates);
                    }
                }
            }
        }
        private IReadOnlyList <RelationshipCandidate> FindRelationshipCandidates(Entity entity)
        {
            var relationshipCandidates = new Dictionary <Type, RelationshipCandidate>();
            var navigationCandidates   = GetNavigationCandidates(entity);

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

                //if (entity.IsIgnored(navigationPropertyInfo.Name))
                //{
                //    continue;
                //}

                var candidateTargetEntity = entity.Model.FindEntity(targetClrType);
                if (candidateTargetEntity == null)
                {
                    continue;
                }

                RelationshipCandidate existingCandidate;
                if (relationshipCandidates.TryGetValue(targetClrType, out existingCandidate))
                {
                    if (candidateTargetEntity != entity || !existingCandidate.InverseProperties.Contains(navigationPropertyInfo))
                    {
                        existingCandidate.NavigationProperties.Add(navigationPropertyInfo);
                    }

                    continue;
                }

                var navigations = new HashSet <PropertyInfo> {
                    navigationPropertyInfo
                };

                var inverseCandidates           = GetNavigationCandidates(candidateTargetEntity);
                var inverseNavigationCandidates = new HashSet <PropertyInfo>();
                foreach (var inverseCandidateTuple in inverseCandidates)
                {
                    var inversePropertyInfo = inverseCandidateTuple.Key;
                    var inverseTargetType   = inverseCandidateTuple.Value;

                    if (inverseTargetType != entity.ClrType || navigationPropertyInfo == inversePropertyInfo /* || candidateTargetEntity.IsIgnored(inversePropertyInfo.Name) */)
                    {
                        continue;
                    }

                    inverseNavigationCandidates.Add(inversePropertyInfo);
                }

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

            return(relationshipCandidates.Values.ToList());
        }
        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.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)
                {
                    continue;
                }

                var candidateTargetEntityType = candidateTargetEntityTypeBuilder.Metadata;
                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.HasDefiningNavigation() &&
                         entityType.DefiningEntityType == candidateTargetEntityType &&
                         entityType.DefiningNavigationName != inversePropertyInfo.Name))
                    {
                        continue;
                    }

                    inverseNavigationCandidates.Add(inversePropertyInfo);
                }

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

            return(relationshipCandidates.Values.ToList());
        }
        private IReadOnlyList <RelationshipCandidate> FindRelationshipCandidates(InternalEntityTypeBuilder entityTypeBuilder)
        {
            var relationshipCandidates = new Dictionary <EntityType, RelationshipCandidate>();
            var ownership = entityTypeBuilder.Metadata.FindOwnership();

            if (ownership == null &&
                entityTypeBuilder.Metadata.Model.ShouldBeOwnedType(entityTypeBuilder.Metadata.ClrType))
            {
                return(relationshipCandidates.Values.ToList());
            }

            var navigationCandidates = GetNavigationCandidates(entityTypeBuilder.Metadata);

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

                if (!IsCandidateNavigationProperty(entityTypeBuilder, navigationPropertyInfo.Name, navigationPropertyInfo))
                {
                    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 targetOwnership = candidateTargetEntityType.FindOwnership();
                    if (targetOwnership != null &&
                        (targetOwnership.PrincipalEntityType != entityTypeBuilder.Metadata ||
                         targetOwnership.PrincipalToDependent.Name != navigationPropertyInfo.Name))
                    {
                        if (ownership == null ||
                            ownership.PrincipalEntityType != candidateTargetEntityType)
                        {
                            continue;
                        }
                    }
                }
                else if (  // #8172
                    //ownership != null &&
                    navigationPropertyInfo.PropertyType.TryGetSequenceType() != null)
                {
                    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) ||
                        entityType.IsQueryType ||
                        (ownership != null &&
                         (ownership.PrincipalEntityType != candidateTargetEntityType ||
                          ownership.PrincipalToDependent.Name != inversePropertyInfo.Name)) ||
                        (entityType.HasDefiningNavigation() &&
                         (entityType.DefiningEntityType != candidateTargetEntityType ||
                          entityType.DefiningNavigationName != inversePropertyInfo.Name)) ||
                        !IsCandidateNavigationProperty(
                            candidateTargetEntityTypeBuilder, inversePropertyInfo.Name, inversePropertyInfo))
                    {
                        continue;
                    }

                    inverseNavigationCandidates.Add(inversePropertyInfo);
                }

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

            return(relationshipCandidates.Values.ToList());
        }
        private IReadOnlyList <RelationshipCandidate> FindRelationshipCandidates(IConventionEntityTypeBuilder entityTypeBuilder)
        {
            var entityType             = entityTypeBuilder.Metadata;
            var model                  = entityType.Model;
            var relationshipCandidates = new Dictionary <IConventionEntityType, RelationshipCandidate>();
            var ownership              = entityTypeBuilder.Metadata.FindOwnership();

            if (ownership == null &&
                model.IsOwned(entityTypeBuilder.Metadata.ClrType))
            {
                return(relationshipCandidates.Values.ToList());
            }

            foreach (var candidateTuple in Dependencies.MemberClassifier.GetNavigationCandidates(entityType))
            {
                var navigationPropertyInfo = candidateTuple.Key;
                var targetClrType          = candidateTuple.Value;

                if (!IsCandidateNavigationProperty(entityTypeBuilder, navigationPropertyInfo.GetSimpleMemberName(), navigationPropertyInfo) ||
                    (model.IsOwned(targetClrType) &&
                     HasDeclaredAmbiguousNavigationsTo(entityType, targetClrType)))
                {
                    continue;
                }

                IConventionEntityTypeBuilder?candidateTargetEntityTypeBuilder = ((InternalEntityTypeBuilder)entityTypeBuilder)
                                                                                .GetTargetEntityTypeBuilder(targetClrType, navigationPropertyInfo, ConfigurationSource.Convention);

                if (candidateTargetEntityTypeBuilder == null)
                {
                    continue;
                }

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

                if (!entityType.IsInModel)
                {
                    foreach (var relationshipCandidate in relationshipCandidates.Values)
                    {
                        var targetType = relationshipCandidate.TargetTypeBuilder.Metadata;
                        if (targetType.IsInModel &&
                            IsImplicitlyCreatedUnusedSharedType(targetType))
                        {
                            targetType.Builder.ModelBuilder.HasNoEntityType(targetType);
                        }
                    }

                    return(Array.Empty <RelationshipCandidate>());
                }

                if (!model.IsOwned(targetClrType))
                {
                    var targetOwnership = candidateTargetEntityType.FindOwnership();
                    if (targetOwnership != null &&
                        (targetOwnership.PrincipalEntityType != entityType ||
                         targetOwnership.PrincipalToDependent?.Name != navigationPropertyInfo.GetSimpleMemberName()) &&
                        (ownership == null ||
                         ownership.PrincipalEntityType != candidateTargetEntityType))
                    {
                        continue;
                    }
                }

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

                    continue;
                }

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

                if (!entityType.IsKeyless)
                {
                    var inverseCandidates = Dependencies.MemberClassifier.GetNavigationCandidates(candidateTargetEntityType);
                    foreach (var inverseCandidateTuple in inverseCandidates)
                    {
                        var inversePropertyInfo = inverseCandidateTuple.Key;
                        var inverseTargetType   = inverseCandidateTuple.Value;

                        if ((inverseTargetType != entityType.ClrType &&
                             (!inverseTargetType.IsAssignableFrom(entityType.ClrType) ||
                              (!model.IsOwned(targetClrType) &&
                               !candidateTargetEntityType.IsInOwnershipPath(entityType)))) ||
                            navigationPropertyInfo.IsSameAs(inversePropertyInfo) ||
                            (ownership != null &&
                             !candidateTargetEntityType.IsInOwnershipPath(entityType) &&
                             (candidateTargetEntityType.IsOwned() ||
                              !model.IsOwned(targetClrType)) &&
                             (ownership.PrincipalEntityType != candidateTargetEntityType ||
                              ownership.PrincipalToDependent?.Name != inversePropertyInfo.GetSimpleMemberName())) ||
                            !IsCandidateNavigationProperty(
                                candidateTargetEntityTypeBuilder, inversePropertyInfo.GetSimpleMemberName(), inversePropertyInfo))
                        {
                            continue;
                        }

                        if (!inverseNavigationCandidates.Contains(inversePropertyInfo))
                        {
                            inverseNavigationCandidates.Add(inversePropertyInfo);
                        }
                    }
                }

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

            var candidates = new List <RelationshipCandidate>();

            foreach (var relationshipCandidate in relationshipCandidates.Values)
            {
                if (relationshipCandidate.TargetTypeBuilder.Metadata.IsInModel)
                {
                    candidates.Add(relationshipCandidate);
                    continue;
                }

                if (relationshipCandidate.NavigationProperties.Count > 1)
                {
                    continue;
                }

                // The entity type might have been converted to a weak entity type
                var actualTargetEntityTypeBuilder =
                    ((InternalEntityTypeBuilder)entityTypeBuilder).GetTargetEntityTypeBuilder(
                        relationshipCandidate.TargetTypeBuilder.Metadata.ClrType,
                        relationshipCandidate.NavigationProperties.Single(),
                        ConfigurationSource.Convention);

                if (actualTargetEntityTypeBuilder == null)
                {
                    continue;
                }

                candidates.Add(
                    new RelationshipCandidate(
                        actualTargetEntityTypeBuilder, relationshipCandidate.NavigationProperties,
                        relationshipCandidate.InverseProperties));
            }

            return(candidates);
        }
        private void RemoveInheritedInverseNavigations(
            RelationshipCandidate relationshipCandidate,
            List<RelationshipCandidate> relationshipCandidatesHierarchy,
            HashSet<RelationshipCandidate> filteredRelationshipCandidates)
        {
            if (filteredRelationshipCandidates.Contains(relationshipCandidate)
                || (relationshipCandidate.NavigationProperties.Count > 1
                    && relationshipCandidate.InverseProperties.Count > 0)
                || relationshipCandidate.InverseProperties.Count > 1)
            {
                return;
            }

            filteredRelationshipCandidates.Add(relationshipCandidate);
            var inverseCandidate = relationshipCandidate.InverseProperties.FirstOrDefault();
            if (inverseCandidate != null)
            {
                var relationshipsToDerivedTypes = relationshipCandidatesHierarchy
                    .Where(r => r.TargetTypeBuilder != relationshipCandidate.TargetTypeBuilder
                                && relationshipCandidate.TargetTypeBuilder.Metadata.IsAssignableFrom(r.TargetTypeBuilder.Metadata));
                foreach (var relationshipToDerivedType in relationshipsToDerivedTypes)
                {
                    relationshipToDerivedType.InverseProperties.RemoveWhere(i => i.Name == inverseCandidate.Name);

                    if (!filteredRelationshipCandidates.Contains(relationshipToDerivedType))
                    {
                        // An ambiguity might have been resolved
                        RemoveInheritedInverseNavigations(relationshipToDerivedType, relationshipCandidatesHierarchy, filteredRelationshipCandidates);
                    }
                }
            }
        }