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); } } } }