Exemplo n.º 1
0
        public virtual InternalPropertyBuilder Attach(
            [NotNull] InternalEntityTypeBuilder entityTypeBuilder, ConfigurationSource configurationSource)
        {
            var newProperty = Metadata.DeclaringEntityType.FindProperty(Metadata.Name);

            Debug.Assert(newProperty != null);
            var newPropertyBuilder = entityTypeBuilder.Property(Metadata.Name, configurationSource);

            if (newProperty == Metadata)
            {
                return(newPropertyBuilder);
            }

            newPropertyBuilder.MergeAnnotationsFrom(this);

            if (Metadata.GetClrTypeConfigurationSource().HasValue)
            {
                newPropertyBuilder.HasClrType(Metadata.ClrType, Metadata.GetClrTypeConfigurationSource().Value);
            }
            if (Metadata.GetIsReadOnlyAfterSaveConfigurationSource().HasValue)
            {
                newPropertyBuilder.ReadOnlyAfterSave(Metadata.IsReadOnlyAfterSave,
                                                     Metadata.GetIsReadOnlyAfterSaveConfigurationSource().Value);
            }
            if (Metadata.GetIsReadOnlyBeforeSaveConfigurationSource().HasValue)
            {
                newPropertyBuilder.ReadOnlyBeforeSave(Metadata.IsReadOnlyBeforeSave,
                                                      Metadata.GetIsReadOnlyBeforeSaveConfigurationSource().Value);
            }
            if (Metadata.GetIsNullableConfigurationSource().HasValue)
            {
                newPropertyBuilder.IsRequired(!Metadata.IsNullable, Metadata.GetIsNullableConfigurationSource().Value);
            }
            if (Metadata.GetIsConcurrencyTokenConfigurationSource().HasValue)
            {
                newPropertyBuilder.IsConcurrencyToken(Metadata.IsConcurrencyToken,
                                                      Metadata.GetIsConcurrencyTokenConfigurationSource().Value);
            }
            if (Metadata.GetIsShadowPropertyConfigurationSource().HasValue)
            {
                newPropertyBuilder.IsShadow(Metadata.IsShadowProperty, Metadata.GetIsShadowPropertyConfigurationSource().Value);
            }
            if (Metadata.GetRequiresValueGeneratorConfigurationSource().HasValue)
            {
                newPropertyBuilder.RequiresValueGenerator(Metadata.RequiresValueGenerator,
                                                          Metadata.GetRequiresValueGeneratorConfigurationSource().Value);
            }
            if (Metadata.GetValueGeneratedConfigurationSource().HasValue)
            {
                newPropertyBuilder.ValueGenerated(Metadata.ValueGenerated, Metadata.GetValueGeneratedConfigurationSource().Value);
            }

            return(newPropertyBuilder);
        }
        private Property CreateUniqueProperty(string baseName, Type propertyType, InternalEntityTypeBuilder entityTypeBuilder, bool?isRequired = null)
        {
            var index = -1;

            while (true)
            {
                var name = baseName + (++index > 0 ? index.ToString() : "");
                if (entityTypeBuilder.Metadata.FindProperty(name) != null)
                {
                    continue;
                }

                var propertyBuilder = entityTypeBuilder.Property(propertyType, name, ConfigurationSource.Convention);
                if (propertyBuilder != null)
                {
                    if (isRequired.HasValue)
                    {
                        propertyBuilder.Required(isRequired.Value, ConfigurationSource.Convention);
                    }
                    return(propertyBuilder.Metadata);
                }
            }
        }
        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);
        }