private ForeignKey CreateForeignKey(
            [NotNull] InternalEntityTypeBuilder principalEntityTypeBuilder,
            [NotNull] InternalEntityTypeBuilder dependentEntityTypeBuilder,
            [CanBeNull] string navigationToPrincipal,
            [CanBeNull] IReadOnlyList <Property> foreignKeyProperties,
            [CanBeNull] IReadOnlyList <Property> principalProperties,
            bool?isUnique,
            bool?isRequired,
            ConfigurationSource configurationSource)
        {
            var principalType = principalEntityTypeBuilder.Metadata;
            var dependentType = dependentEntityTypeBuilder.Metadata;

            if (foreignKeyProperties != null &&
                dependentType.FindForeignKey(foreignKeyProperties) != null)
            {
                return(null);
            }

            if (foreignKeyProperties != null &&
                principalProperties != null)
            {
                Entity.Metadata.Property.EnsureCompatible(principalProperties, foreignKeyProperties);
            }

            Key principalKey;

            if (principalProperties != null)
            {
                var keyBuilder = principalEntityTypeBuilder.Key(principalProperties, configurationSource);
                if (keyBuilder == null)
                {
                    return(null);
                }
                principalKey = keyBuilder.Metadata;
            }
            else
            {
                principalKey = principalType.FindPrimaryKey();
            }

            if (foreignKeyProperties != null)
            {
                if (principalKey == null ||
                    !Entity.Metadata.Property.AreCompatible(principalKey.Properties, foreignKeyProperties))
                {
                    var principalKeyProperties = new Property[foreignKeyProperties.Count];
                    for (var i = 0; i < foreignKeyProperties.Count; i++)
                    {
                        var foreignKeyProperty = foreignKeyProperties[i];
                        principalKeyProperties[i] = CreateUniqueProperty(
                            foreignKeyProperty.Name,
                            foreignKeyProperty.ClrType,
                            principalEntityTypeBuilder,
                            isRequired);
                    }

                    var keyBuilder = principalEntityTypeBuilder.Key(principalKeyProperties, ConfigurationSource.Convention);

                    principalKey = keyBuilder.Metadata;
                }
            }
            else
            {
                var baseName = (string.IsNullOrEmpty(navigationToPrincipal) ? principalType.DisplayName() : navigationToPrincipal);

                if (principalKey == null)
                {
                    var principalKeyProperty = CreateUniqueProperty(
                        "TempId",
                        typeof(int),
                        principalEntityTypeBuilder,
                        isRequired);

                    principalKey = principalEntityTypeBuilder.Key(new[] { principalKeyProperty }, ConfigurationSource.Convention).Metadata;
                }

                var fkProperties = new Property[principalKey.Properties.Count];
                for (var i = 0; i < principalKey.Properties.Count; i++)
                {
                    var keyProperty = principalKey.Properties[i];
                    fkProperties[i] = CreateUniqueProperty(
                        baseName + keyProperty.Name,
                        keyProperty.ClrType.MakeNullable(),
                        dependentEntityTypeBuilder,
                        isRequired);
                }

                foreignKeyProperties = fkProperties;
            }

            var newForeignKey = dependentType.AddForeignKey(foreignKeyProperties, principalKey);

            newForeignKey.IsUnique = isUnique;

            foreach (var foreignKeyProperty in foreignKeyProperties)
            {
                var propertyBuilder = dependentEntityTypeBuilder.Property(
                    foreignKeyProperty.ClrType, foreignKeyProperty.Name, ConfigurationSource.Convention);

                propertyBuilder.GenerateValueOnAdd(null, ConfigurationSource.Convention);
                propertyBuilder.StoreGeneratedPattern(null, ConfigurationSource.Convention);
            }

            return(newForeignKey);
        }
        public virtual InternalRelationshipBuilder Relationship(
            [NotNull] InternalEntityTypeBuilder principalEntityTypeBuilder,
            [NotNull] InternalEntityTypeBuilder dependentEntityTypeBuilder,
            [CanBeNull] string navigationToPrincipalName,
            [CanBeNull] string navigationToDependentName,
            [CanBeNull] IReadOnlyList <Property> foreignKeyProperties,
            [CanBeNull] IReadOnlyList <Property> principalProperties,
            ConfigurationSource configurationSource,
            bool?isUnique   = null,
            bool?isRequired = null,
            [CanBeNull] Func <InternalRelationshipBuilder, InternalRelationshipBuilder> onRelationshipAdding = null)
        {
            var principalType = principalEntityTypeBuilder.Metadata;
            var dependentType = dependentEntityTypeBuilder.Metadata;

            if (foreignKeyProperties != null &&
                foreignKeyProperties.Count == 0)
            {
                foreignKeyProperties = null;
            }

            if (principalProperties != null &&
                principalProperties.Count == 0)
            {
                principalProperties = null;
            }

            var foreignKey = foreignKeyProperties == null
                ? null
                : dependentType.FindForeignKey(
                principalType,
                null,
                null,
                foreignKeyProperties,
                principalProperties,
                isUnique);

            var existingForeignKey = foreignKey != null;

            if (!existingForeignKey)
            {
                if (foreignKeyProperties != null)
                {
                    var conflictingForeignKey = dependentType.FindForeignKey(foreignKeyProperties);
                    if (conflictingForeignKey != null &&
                        !dependentEntityTypeBuilder.RemoveRelationship(conflictingForeignKey, configurationSource).HasValue)
                    {
                        return(null);
                    }
                }

                foreignKey = CreateForeignKey(
                    principalEntityTypeBuilder,
                    dependentEntityTypeBuilder,
                    navigationToPrincipalName,
                    foreignKeyProperties,
                    principalProperties,
                    isUnique,
                    isRequired,
                    configurationSource);

                if (foreignKey == null)
                {
                    return(null);
                }
            }

            if (isRequired.HasValue)
            {
                var properties = foreignKey.Properties;
                if (!isRequired.Value)
                {
                    var nullableTypeProperties = properties.Where(p => p.ClrType.IsNullableType()).ToList();
                    if (nullableTypeProperties.Any())
                    {
                        properties = nullableTypeProperties;
                    }
                }

                foreach (var property in properties)
                {
                    if (!dependentEntityTypeBuilder.Property(property.ClrType, property.Name, ConfigurationSource.Convention)
                        .CanSetRequired(isRequired.Value, configurationSource))
                    {
                        if (!existingForeignKey)
                        {
                            dependentType.RemoveForeignKey(foreignKey);
                        }

                        // TODO: throw for explicit
                        return(null);
                    }
                }

                foreach (var property in properties)
                {
                    // TODO: Depending on resolution of #723 this may change
                    var requiredSet = dependentEntityTypeBuilder.Property(property.ClrType, property.Name, ConfigurationSource.Convention)
                                      .Required(isRequired.Value, configurationSource);
                    Debug.Assert(requiredSet);
                }

                foreignKey.IsRequired = isRequired.Value;
            }

            var builder = Relationship(foreignKey, existingForeignKey, configurationSource);

            Debug.Assert(builder != null);

            var navigationToPrincipalSet = dependentEntityTypeBuilder
                                           .Navigation(navigationToPrincipalName, foreignKey, pointsToPrincipal: true, configurationSource: configurationSource);

            Debug.Assert(navigationToPrincipalSet);

            var navigationToDependentSet = principalEntityTypeBuilder
                                           .Navigation(navigationToDependentName, foreignKey, pointsToPrincipal: false, configurationSource: configurationSource);

            Debug.Assert(navigationToDependentSet);

            if (onRelationshipAdding != null)
            {
                builder = onRelationshipAdding(builder);
            }
            else
            {
                if (isUnique.HasValue)
                {
                    builder = builder.Unique(isUnique.Value, configurationSource);
                }
                if (isRequired.HasValue)
                {
                    builder = builder.Required(isRequired.Value, configurationSource);
                }
                if (foreignKeyProperties != null)
                {
                    builder = builder.ForeignKey(foreignKeyProperties, configurationSource);
                }
                if (principalProperties != null)
                {
                    builder = builder.PrincipalKey(principalProperties, configurationSource);
                }
            }

            if (!existingForeignKey)
            {
                builder = ModelBuilder.ConventionDispatcher.OnForeignKeyAdded(builder);
            }

            return(builder);
        }
Beispiel #3
0
 public static RelationalEntityTypeBuilderAnnotations SqlServer(
     [NotNull] this InternalEntityTypeBuilder builder,
     ConfigurationSource configurationSource)
 => new RelationalEntityTypeBuilderAnnotations(builder, configurationSource, SqlServerAnnotationNames.Prefix);
        public virtual InternalRelationshipBuilder Relationship(
            [NotNull] InternalEntityTypeBuilder principalEntityTypeBuilder,
            [NotNull] InternalEntityTypeBuilder dependentEntityTypeBuilder,
            [CanBeNull] string navigationToPrincipalName,
            [CanBeNull] string navigationToDependentName,
            ConfigurationSource configurationSource,
            bool?isUnique        = null,
            bool strictPrincipal = true)
        {
            Check.NotNull(principalEntityTypeBuilder, nameof(principalEntityTypeBuilder));
            Check.NotNull(dependentEntityTypeBuilder, nameof(dependentEntityTypeBuilder));

            if (dependentEntityTypeBuilder != this)
            {
                return(dependentEntityTypeBuilder.Relationship(
                           principalEntityTypeBuilder,
                           dependentEntityTypeBuilder,
                           navigationToPrincipalName,
                           navigationToDependentName,
                           configurationSource,
                           isUnique,
                           strictPrincipal));
            }

            if (!string.IsNullOrEmpty(navigationToPrincipalName) &&
                !dependentEntityTypeBuilder.CanAdd(navigationToPrincipalName, isNavigation: true, configurationSource: configurationSource))
            {
                return(null);
            }

            if (!string.IsNullOrEmpty(navigationToDependentName) &&
                !principalEntityTypeBuilder.CanAdd(navigationToDependentName, isNavigation: true, configurationSource: configurationSource))
            {
                return(null);
            }

            var principalEntityType = principalEntityTypeBuilder.Metadata;
            var dependentEntityType = dependentEntityTypeBuilder.Metadata;

            var navigationToPrincipal = string.IsNullOrEmpty(navigationToPrincipalName)
                ? null
                : dependentEntityType.FindNavigation(navigationToPrincipalName);

            if (navigationToPrincipal != null &&
                navigationToPrincipal.IsCompatible(principalEntityType, dependentEntityType, strictPrincipal ? (bool?)true : null, isUnique))
            {
                return(Relationship(navigationToPrincipal, configurationSource, navigationToDependentName));
            }

            var navigationToDependent = string.IsNullOrEmpty(navigationToDependentName)
                ? null
                : principalEntityType.FindNavigation(navigationToDependentName);

            if (navigationToDependent != null &&
                navigationToDependent.IsCompatible(principalEntityType, dependentEntityType, strictPrincipal ? (bool?)false : null, isUnique))
            {
                return(Relationship(navigationToDependent, configurationSource, navigationToPrincipalName));
            }

            if (!RemoveRelationships(configurationSource, navigationToPrincipal?.ForeignKey, navigationToDependent?.ForeignKey))
            {
                return(null);
            }

            navigationToPrincipalName = navigationToPrincipalName == "" ? null : navigationToPrincipalName;
            navigationToDependentName = navigationToDependentName == "" ? null : navigationToDependentName;

            return(Relationship(
                       principalEntityTypeBuilder,
                       dependentEntityTypeBuilder,
                       navigationToPrincipalName,
                       navigationToDependentName,
                       null,
                       null,
                       configurationSource,
                       isUnique));
        }
 public static RelationalEntityTypeBuilderAnnotations Relational(
     [NotNull] this InternalEntityTypeBuilder builder,
     ConfigurationSource configurationSource)
 => new RelationalEntityTypeBuilderAnnotations(builder, configurationSource, null);