/// <summary> /// Generates a unique name for the new joint entity type. /// </summary> /// <param name="skipNavigation">The target skip navigation.</param> /// <returns>A unique entity type name.</returns> protected virtual string GenerateJoinTypeName(IConventionSkipNavigation skipNavigation) { var inverseSkipNavigation = skipNavigation.Inverse; Check.DebugAssert( inverseSkipNavigation?.Inverse == skipNavigation, "Inverse's inverse should be the original skip navigation"); var declaringEntityType = skipNavigation.DeclaringEntityType; var inverseEntityType = inverseSkipNavigation.DeclaringEntityType; var model = declaringEntityType.Model; var joinEntityTypeName = declaringEntityType.ShortName(); var inverseName = inverseEntityType.ShortName(); joinEntityTypeName = StringComparer.Ordinal.Compare(joinEntityTypeName, inverseName) < 0 ? joinEntityTypeName + inverseName : inverseName + joinEntityTypeName; if (model.FindEntityType(joinEntityTypeName) != null) { var otherIdentifiers = model.GetEntityTypes().ToDictionary(et => et.Name, _ => 0); joinEntityTypeName = Uniquifier.Uniquify( joinEntityTypeName, otherIdentifiers, int.MaxValue); } return(joinEntityTypeName); }
private void CreateJoinEntityType(IConventionSkipNavigationBuilder skipNavigationBuilder) { var skipNavigation = (SkipNavigation)skipNavigationBuilder.Metadata; if (skipNavigation.ForeignKey != null || !skipNavigation.IsCollection) { return; } var inverseSkipNavigation = skipNavigation.Inverse; if (inverseSkipNavigation == null || inverseSkipNavigation.ForeignKey != null || !inverseSkipNavigation.IsCollection) { return; } Check.DebugAssert(inverseSkipNavigation.Inverse == skipNavigation, "Inverse's inverse should be the original skip navigation"); var declaringEntityType = skipNavigation.DeclaringEntityType; var inverseEntityType = inverseSkipNavigation.DeclaringEntityType; var model = declaringEntityType.Model; var joinEntityTypeName = declaringEntityType.ShortName() + inverseEntityType.ShortName(); if (model.FindEntityType(joinEntityTypeName) != null) { var otherIdentifiers = model.GetEntityTypes().ToDictionary(et => et.Name, et => 0); joinEntityTypeName = Uniquifier.Uniquify( joinEntityTypeName, otherIdentifiers, int.MaxValue); } var joinEntityTypeBuilder = model.Builder.SharedTypeEntity( joinEntityTypeName, Model.DefaultPropertyBagType, ConfigurationSource.Convention); var leftForeignKey = CreateSkipNavigationForeignKey(skipNavigation, joinEntityTypeBuilder); if (leftForeignKey == null) { model.Builder.HasNoEntityType(joinEntityTypeBuilder.Metadata, ConfigurationSource.Convention); return; } var rightForeignKey = CreateSkipNavigationForeignKey(inverseSkipNavigation, joinEntityTypeBuilder); if (rightForeignKey == null) { model.Builder.HasNoEntityType(joinEntityTypeBuilder.Metadata, ConfigurationSource.Convention); return; } skipNavigation.Builder.HasForeignKey(leftForeignKey, ConfigurationSource.Convention); inverseSkipNavigation.Builder.HasForeignKey(rightForeignKey, ConfigurationSource.Convention); }
/// <inheritdoc /> public virtual void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext <IConventionModelBuilder> context) { var model = modelBuilder.Metadata; var modelSequences = (SortedDictionary <(string Name, string Schema), Sequence>)model[RelationalAnnotationNames.Sequences]; if (modelSequences != null) { var maxLength = model.GetMaxIdentifierLength(); var toReplace = modelSequences .Where(s => s.Key.Name.Length > maxLength).ToList(); foreach (var sequence in toReplace) { var schemaName = sequence.Key.Schema; var newSequenceName = Uniquifier.Uniquify( sequence.Key.Name, modelSequences, sequenceName => (sequenceName, schemaName), maxLength); Sequence.SetName((IMutableModel)model, sequence.Value, newSequenceName); } } }
private static ForeignKey CreateSkipNavigationForeignKey( SkipNavigation skipNavigation, InternalEntityTypeBuilder associationEntityTypeBuilder) { var principalEntityType = skipNavigation.DeclaringEntityType; var principalKey = principalEntityType.FindPrimaryKey(); if (principalKey == null) { return(null); } var dependentEndForeignKeyPropertyNames = new List <string>(); var otherIdentifiers = associationEntityTypeBuilder.Metadata .GetDeclaredProperties().ToDictionary(p => p.Name, p => 0); foreach (var property in principalKey.Properties) { var propertyName = Uniquifier.Uniquify( string.Format( AssociationPropertyNameTemplate, principalEntityType.ShortName(), property.Name), otherIdentifiers, int.MaxValue); dependentEndForeignKeyPropertyNames.Add(propertyName); otherIdentifiers.Add(propertyName, 0); } return(associationEntityTypeBuilder .HasRelationship( principalEntityType.Name, dependentEndForeignKeyPropertyNames, principalKey, ConfigurationSource.Convention) .IsUnique(false, ConfigurationSource.Convention) .Metadata); }
private void CreateAssociationEntityType( IConventionSkipNavigationBuilder skipNavigationBuilder) { var skipNavigation = (SkipNavigation)skipNavigationBuilder.Metadata; if (skipNavigation.AssociationEntityType != null) { return; } if (skipNavigation.ForeignKey != null || skipNavigation.TargetEntityType == skipNavigation.DeclaringEntityType || !skipNavigation.IsCollection) { // do not create the association entity type for a self-referencing // skip navigation, or for one that is already "in use" // (i.e. has its Foreign Key assigned). return; } var inverseSkipNavigation = skipNavigation.Inverse; if (inverseSkipNavigation == null || inverseSkipNavigation.ForeignKey != null || !inverseSkipNavigation.IsCollection) { // do not create the association entity type if // the inverse skip navigation is already "in use" // (i.e. has its Foreign Key assigned). return; } Check.DebugAssert(inverseSkipNavigation.Inverse == skipNavigation, "Inverse's inverse should be the original skip navigation"); var declaringEntityType = skipNavigation.DeclaringEntityType; var inverseEntityType = inverseSkipNavigation.DeclaringEntityType; var model = declaringEntityType.Model; // create the association entity type var associationEntityTypeName = string.Format( AssociationEntityTypeNameTemplate, declaringEntityType.ShortName(), inverseEntityType.ShortName()); if (model.FindEntityType(associationEntityTypeName) != null) { var otherIdentifiers = model.GetEntityTypes().ToDictionary(et => et.Name, et => 0); associationEntityTypeName = Uniquifier.Uniquify( associationEntityTypeName, otherIdentifiers, int.MaxValue); } var associationEntityTypeBuilder = model.Builder.SharedEntity( associationEntityTypeName, Model.DefaultPropertyBagType, ConfigurationSource.Convention); // Create left and right foreign keys from the outer entity types to // the association entity type and configure the skip navigations. // Roll back if any of this fails. var leftForeignKey = CreateSkipNavigationForeignKey(skipNavigation, associationEntityTypeBuilder); if (leftForeignKey == null) { model.Builder.HasNoEntityType( associationEntityTypeBuilder.Metadata, ConfigurationSource.Convention); return; } var rightForeignKey = CreateSkipNavigationForeignKey(inverseSkipNavigation, associationEntityTypeBuilder); if (rightForeignKey == null) { // Removing the association entity type will also remove // the leftForeignKey created above. model.Builder.HasNoEntityType( associationEntityTypeBuilder.Metadata, ConfigurationSource.Convention); return; } skipNavigation.Builder.HasForeignKey(leftForeignKey, ConfigurationSource.Convention); inverseSkipNavigation.Builder.HasForeignKey(rightForeignKey, ConfigurationSource.Convention); // Creating the primary key below also negates the need for an index on // the properties of leftForeignKey - that index is automatically removed. associationEntityTypeBuilder.PrimaryKey( leftForeignKey.Properties.Concat(rightForeignKey.Properties).ToList(), ConfigurationSource.Convention); }