Exemple #1
0
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        protected virtual void ValidateNoSchemas([NotNull] IModel model, DiagnosticsLoggers loggers)
        {
            var logger = loggers.GetLogger <DbLoggerCategory.Model.Validation>();

            foreach (var entityType in model.GetEntityTypes().Where(e => e.GetSchema() != null))
            {
                logger.SchemaConfiguredWarning(entityType, entityType.GetSchema());
            }
        }
Exemple #2
0
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        protected virtual void ValidateNoSequences([NotNull] IModel model, DiagnosticsLoggers loggers)
        {
            var logger = loggers.GetLogger <DbLoggerCategory.Model.Validation>();

            foreach (var sequence in model.GetSequences())
            {
                logger.SequenceConfiguredWarning(sequence);
            }
        }
Exemple #3
0
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        protected virtual void ValidateByteIdentityMapping([NotNull] IModel model, DiagnosticsLoggers loggers)
        {
            var logger = loggers.GetLogger <DbLoggerCategory.Model.Validation>();

            foreach (var property in model.GetEntityTypes()
                     .SelectMany(t => t.GetDeclaredProperties())
                     .Where(
                         p => p.ClrType.UnwrapNullableType() == typeof(byte) &&
                         p.GetSqlServerValueGenerationStrategy() == SqlServerValueGenerationStrategy.IdentityColumn))
            {
                logger.ByteIdentityColumnWarning(property);
            }
        }
        /// <summary>
        ///     Validates the mapping/configuration of <see cref="bool"/> properties in the model.
        /// </summary>
        /// <param name="model"> The model to validate. </param>
        /// <param name="loggers"> Loggers to use if needed. </param>
        protected virtual void ValidateBoolsWithDefaults([NotNull] IModel model, DiagnosticsLoggers loggers)
        {
            Check.NotNull(model, nameof(model));

            var logger = loggers.GetLogger <DbLoggerCategory.Model.Validation>();

            foreach (var property in model.GetEntityTypes().SelectMany(e => e.GetDeclaredProperties()))
            {
                if (property.ClrType == typeof(bool) &&
                    property.ValueGenerated != ValueGenerated.Never &&
                    (IsNotNullAndFalse(property.Relational().DefaultValue) ||
                     property.Relational().DefaultValueSql != null))
                {
                    logger.BoolWithDefaultWarning(property);
                }
            }
        }
        /// <summary>
        ///     Logs all shadow properties that were created because there was no matching CLR member.
        /// </summary>
        /// <param name="model"> The model to validate. </param>
        /// <param name="loggers"> Loggers to use if needed. </param>
        protected virtual void LogShadowProperties([NotNull] IModel model, DiagnosticsLoggers loggers)
        {
            Check.NotNull(model, nameof(model));

            var modelLogger = loggers.GetLogger <DbLoggerCategory.Model>();

            foreach (var entityType in model.GetEntityTypes().Where(t => t.ClrType != null))
            {
                foreach (var property in entityType.GetDeclaredProperties())
                {
                    if (property.IsShadowProperty())
                    {
                        modelLogger.ShadowPropertyCreated(property);
                    }
                }
            }
        }
        /// <summary>
        ///     Validates the mapping/configuration of foreign keys in the model.
        /// </summary>
        /// <param name="model"> The model to validate. </param>
        /// <param name="loggers"> Loggers to use if needed. </param>
        protected virtual void ValidateForeignKeys([NotNull] IModel model, DiagnosticsLoggers loggers)
        {
            var modelLogger = loggers.GetLogger <DbLoggerCategory.Model>();

            foreach (var entityType in model.GetEntityTypes())
            {
                foreach (var declaredForeignKey in entityType.GetDeclaredForeignKeys())
                {
                    if (declaredForeignKey.PrincipalEntityType == declaredForeignKey.DeclaringEntityType &&
                        PropertyListComparer.Instance.Equals(declaredForeignKey.PrincipalKey.Properties, declaredForeignKey.Properties))
                    {
                        modelLogger.RedundantForeignKeyWarning(declaredForeignKey);
                    }

                    if (entityType.BaseType == null)
                    {
                        continue;
                    }

                    var inheritedKey = declaredForeignKey.Properties.Where(p => p.ValueGenerated != ValueGenerated.Never)
                                       .SelectMany(p => p.GetContainingKeys().Where(k => k.DeclaringEntityType != entityType)).FirstOrDefault();
                    if (inheritedKey != null)
                    {
                        var generatedProperty = declaredForeignKey.Properties.First(
                            p => p.ValueGenerated != ValueGenerated.Never && inheritedKey.Properties.Contains(p));

                        if (entityType.BaseType.ClrType.IsAbstract &&
                            entityType.BaseType.GetDerivedTypes().All(
                                d => d.GetDeclaredForeignKeys().Any(fk => fk.Properties.Contains(generatedProperty))))
                        {
                            continue;
                        }

                        throw new InvalidOperationException(
                                  CoreStrings.ForeignKeyPropertyInKey(
                                      generatedProperty.Name,
                                      entityType.DisplayName(),
                                      inheritedKey.Properties.Format(),
                                      inheritedKey.DeclaringEntityType.DisplayName()));
                    }
                }
            }
        }
Exemple #7
0
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        protected virtual void ValidateDefaultDecimalMapping([NotNull] IModel model, DiagnosticsLoggers loggers)
        {
            var logger = loggers.GetLogger <DbLoggerCategory.Model.Validation>();

            foreach (var property in model.GetEntityTypes()
                     .SelectMany(t => t.GetDeclaredProperties())
                     .Where(
                         p => p.ClrType.UnwrapNullableType() == typeof(decimal) &&
                         !p.IsForeignKey()))
            {
#pragma warning disable IDE0019 // Use pattern matching
                var type = property.FindAnnotation(RelationalAnnotationNames.ColumnType) as ConventionAnnotation;
#pragma warning restore IDE0019 // Use pattern matching
                var typeMapping = property.FindAnnotation(CoreAnnotationNames.TypeMapping) as ConventionAnnotation;
                if ((type == null &&
                     (typeMapping == null ||
                      ConfigurationSource.Convention.Overrides(typeMapping.GetConfigurationSource()))) ||
                    (type != null &&
                     ConfigurationSource.Convention.Overrides(type.GetConfigurationSource())))
                {
                    logger.DecimalTypeDefaultWarning(property);
                }
            }
        }
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public virtual ConventionSet CreateConventionSet(DiagnosticsLoggers loggers)
        {
            var conventionSet = new ConventionSet();
            var logger        = loggers.GetLogger <DbLoggerCategory.Model>();

            var propertyDiscoveryConvention
                = new PropertyDiscoveryConvention(
                      Dependencies.TypeMappingSource, logger);

            var keyDiscoveryConvention
                = new KeyDiscoveryConvention(logger);

            var inversePropertyAttributeConvention
                = new InversePropertyAttributeConvention(Dependencies.MemberClassifier, logger);

            var relationshipDiscoveryConvention
                = new RelationshipDiscoveryConvention(Dependencies.MemberClassifier, logger);

            var servicePropertyDiscoveryConvention
                = new ServicePropertyDiscoveryConvention(Dependencies.TypeMappingSource, Dependencies.ParameterBindingFactories, logger);

            conventionSet.EntityTypeAddedConventions.Add(new NotMappedEntityTypeAttributeConvention(logger));
            conventionSet.EntityTypeAddedConventions.Add(new OwnedEntityTypeAttributeConvention(logger));
            conventionSet.EntityTypeAddedConventions.Add(new NotMappedMemberAttributeConvention(logger));
            conventionSet.EntityTypeAddedConventions.Add(new BaseTypeDiscoveryConvention(logger));
            conventionSet.EntityTypeAddedConventions.Add(propertyDiscoveryConvention);
            conventionSet.EntityTypeAddedConventions.Add(servicePropertyDiscoveryConvention);
            conventionSet.EntityTypeAddedConventions.Add(keyDiscoveryConvention);
            conventionSet.EntityTypeAddedConventions.Add(inversePropertyAttributeConvention);
            conventionSet.EntityTypeAddedConventions.Add(relationshipDiscoveryConvention);
            conventionSet.EntityTypeAddedConventions.Add(new DerivedTypeDiscoveryConvention(logger));

            conventionSet.EntityTypeIgnoredConventions.Add(inversePropertyAttributeConvention);

            conventionSet.EntityTypeRemovedConventions.Add(new OwnedTypesConvention(logger));

            var foreignKeyIndexConvention = new ForeignKeyIndexConvention(logger);
            var valueGeneratorConvention  = new ValueGeneratorConvention(logger);

            conventionSet.BaseEntityTypeChangedConventions.Add(propertyDiscoveryConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(servicePropertyDiscoveryConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(keyDiscoveryConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(inversePropertyAttributeConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(relationshipDiscoveryConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(foreignKeyIndexConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(valueGeneratorConvention);

            var foreignKeyPropertyDiscoveryConvention = new ForeignKeyPropertyDiscoveryConvention(logger);

            conventionSet.EntityTypeMemberIgnoredConventions.Add(inversePropertyAttributeConvention);
            conventionSet.EntityTypeMemberIgnoredConventions.Add(relationshipDiscoveryConvention);
            conventionSet.EntityTypeMemberIgnoredConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.EntityTypeMemberIgnoredConventions.Add(servicePropertyDiscoveryConvention);

            var keyAttributeConvention = new KeyAttributeConvention(logger);
            var backingFieldConvention = new BackingFieldConvention(logger);
            var concurrencyCheckAttributeConvention  = new ConcurrencyCheckAttributeConvention(logger);
            var databaseGeneratedAttributeConvention = new DatabaseGeneratedAttributeConvention(logger);
            var requiredPropertyAttributeConvention  = new RequiredPropertyAttributeConvention(logger);
            var maxLengthAttributeConvention         = new MaxLengthAttributeConvention(logger);
            var stringLengthAttributeConvention      = new StringLengthAttributeConvention(logger);
            var timestampAttributeConvention         = new TimestampAttributeConvention(logger);

            conventionSet.PropertyAddedConventions.Add(backingFieldConvention);
            conventionSet.PropertyAddedConventions.Add(concurrencyCheckAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(databaseGeneratedAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(requiredPropertyAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(maxLengthAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(stringLengthAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(timestampAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(keyAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(keyDiscoveryConvention);
            conventionSet.PropertyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);

            conventionSet.PrimaryKeyChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.PrimaryKeyChangedConventions.Add(valueGeneratorConvention);

            conventionSet.KeyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.KeyAddedConventions.Add(foreignKeyIndexConvention);

            conventionSet.KeyRemovedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.KeyRemovedConventions.Add(foreignKeyIndexConvention);
            conventionSet.KeyRemovedConventions.Add(keyDiscoveryConvention);

            var cascadeDeleteConvention       = new CascadeDeleteConvention(logger);
            var foreignKeyAttributeConvention = new ForeignKeyAttributeConvention(Dependencies.MemberClassifier, logger);

            conventionSet.ForeignKeyAddedConventions.Add(foreignKeyAttributeConvention);
            conventionSet.ForeignKeyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.ForeignKeyAddedConventions.Add(keyDiscoveryConvention);
            conventionSet.ForeignKeyAddedConventions.Add(valueGeneratorConvention);
            conventionSet.ForeignKeyAddedConventions.Add(cascadeDeleteConvention);
            conventionSet.ForeignKeyAddedConventions.Add(foreignKeyIndexConvention);

            conventionSet.ForeignKeyRemovedConventions.Add(keyDiscoveryConvention);
            conventionSet.ForeignKeyRemovedConventions.Add(valueGeneratorConvention);
            conventionSet.ForeignKeyRemovedConventions.Add(foreignKeyIndexConvention);

            conventionSet.ForeignKeyUniquenessChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.ForeignKeyUniquenessChangedConventions.Add(keyDiscoveryConvention);
            conventionSet.ForeignKeyUniquenessChangedConventions.Add(foreignKeyIndexConvention);

            conventionSet.ForeignKeyRequirednessChangedConventions.Add(cascadeDeleteConvention);
            conventionSet.ForeignKeyRequirednessChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);

            conventionSet.ForeignKeyOwnershipChangedConventions.Add(new NavigationEagerLoadingConvention(logger));
            conventionSet.ForeignKeyOwnershipChangedConventions.Add(keyDiscoveryConvention);
            conventionSet.ForeignKeyOwnershipChangedConventions.Add(relationshipDiscoveryConvention);

            conventionSet.ModelBuiltConventions.Add(new ModelCleanupConvention(logger));
            conventionSet.ModelBuiltConventions.Add(keyAttributeConvention);
            conventionSet.ModelBuiltConventions.Add(foreignKeyAttributeConvention);
            conventionSet.ModelBuiltConventions.Add(new ChangeTrackingStrategyConvention(logger));
            conventionSet.ModelBuiltConventions.Add(new ConstructorBindingConvention(Dependencies.ConstructorBindingFactory, logger));
            conventionSet.ModelBuiltConventions.Add(new TypeMappingConvention(Dependencies.TypeMappingSource, logger));
            conventionSet.ModelBuiltConventions.Add(new IgnoredMembersValidationConvention(logger));
            conventionSet.ModelBuiltConventions.Add(foreignKeyIndexConvention);

            conventionSet.ModelBuiltConventions.Add(
                new PropertyMappingValidationConvention(
                    Dependencies.TypeMappingSource,
                    Dependencies.MemberClassifier,
                    logger));

            conventionSet.ModelBuiltConventions.Add(new RelationshipValidationConvention(logger));
            conventionSet.ModelBuiltConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.ModelBuiltConventions.Add(servicePropertyDiscoveryConvention);
            conventionSet.ModelBuiltConventions.Add(new CacheCleanupConvention(logger));

            conventionSet.NavigationAddedConventions.Add(backingFieldConvention);
            conventionSet.NavigationAddedConventions.Add(new RequiredNavigationAttributeConvention(logger));
            conventionSet.NavigationAddedConventions.Add(inversePropertyAttributeConvention);
            conventionSet.NavigationAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.NavigationAddedConventions.Add(relationshipDiscoveryConvention);

            conventionSet.NavigationRemovedConventions.Add(relationshipDiscoveryConvention);

            conventionSet.IndexAddedConventions.Add(foreignKeyIndexConvention);

            conventionSet.IndexRemovedConventions.Add(foreignKeyIndexConvention);

            conventionSet.IndexUniquenessChangedConventions.Add(foreignKeyIndexConvention);

            conventionSet.PrincipalEndChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);

            conventionSet.PropertyNullabilityChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);

            conventionSet.PropertyFieldChangedConventions.Add(keyDiscoveryConvention);
            conventionSet.PropertyFieldChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.PropertyFieldChangedConventions.Add(keyAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(concurrencyCheckAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(databaseGeneratedAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(requiredPropertyAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(maxLengthAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(stringLengthAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(timestampAttributeConvention);

            return(conventionSet);
        }
        /// <summary>
        ///     Validates the mapping/configuration of data (e.g. seed data) in the model.
        /// </summary>
        /// <param name="model"> The model to validate. </param>
        /// <param name="loggers"> Loggers to use if needed. </param>
        protected virtual void ValidateData([NotNull] IModel model, DiagnosticsLoggers loggers)
        {
            Check.NotNull(model, nameof(model));

            var identityMaps        = new Dictionary <IKey, IIdentityMap>();
            var sensitiveDataLogged = loggers.GetLogger <DbLoggerCategory.Model.Validation>().ShouldLogSensitiveData();

            foreach (var entityType in model.GetEntityTypes())
            {
                var key = entityType.FindPrimaryKey();
                if (key == null)
                {
                    continue;
                }

                IIdentityMap identityMap = null;
                foreach (var seedDatum in entityType.GetSeedData())
                {
                    foreach (var property in entityType.GetProperties())
                    {
                        if (!seedDatum.TryGetValue(property.Name, out var value) ||
                            value == null)
                        {
                            if (!property.IsNullable &&
                                ((!property.RequiresValueGenerator() &&
                                  (property.ValueGenerated & ValueGenerated.OnAdd) == 0) ||
                                 property.IsPrimaryKey()))
                            {
                                throw new InvalidOperationException(CoreStrings.SeedDatumMissingValue(entityType.DisplayName(), property.Name));
                            }
                        }
                        else if (property.RequiresValueGenerator() &&
                                 property.IsPrimaryKey() &&
                                 property.ClrType.IsDefaultValue(value))
                        {
                            if (property.ClrType.IsSignedInteger())
                            {
                                throw new InvalidOperationException(CoreStrings.SeedDatumSignedNumericValue(entityType.DisplayName(), property.Name));
                            }

                            throw new InvalidOperationException(CoreStrings.SeedDatumDefaultValue(entityType.DisplayName(), property.Name, property.ClrType.GetDefaultValue()));
                        }
                        else if (!property.ClrType.GetTypeInfo().IsAssignableFrom(value.GetType().GetTypeInfo()))
                        {
                            if (sensitiveDataLogged)
                            {
                                throw new InvalidOperationException(
                                          CoreStrings.SeedDatumIncompatibleValueSensitive(
                                              entityType.DisplayName(), value, property.Name, property.ClrType.DisplayName()));
                            }

                            throw new InvalidOperationException(
                                      CoreStrings.SeedDatumIncompatibleValue(
                                          entityType.DisplayName(), property.Name, property.ClrType.DisplayName()));
                        }
                    }

                    var keyValues = new object[key.Properties.Count];
                    for (var i = 0; i < key.Properties.Count; i++)
                    {
                        keyValues[i] = seedDatum[key.Properties[i].Name];
                    }

                    foreach (var navigation in entityType.GetNavigations())
                    {
                        if (seedDatum.TryGetValue(navigation.Name, out var value) &&
                            ((navigation.IsCollection() && value is IEnumerable collection && collection.Any()) ||
                             (!navigation.IsCollection() && value != null)))
                        {
                            if (sensitiveDataLogged)
                            {
                                throw new InvalidOperationException(
                                          CoreStrings.SeedDatumNavigationSensitive(
                                              entityType.DisplayName(),
                                              string.Join(", ", key.Properties.Select((p, i) => p.Name + ":" + keyValues[i])),
                                              navigation.Name,
                                              navigation.GetTargetType().DisplayName(),
                                              navigation.ForeignKey.Properties.Format()));
                            }

                            throw new InvalidOperationException(
                                      CoreStrings.SeedDatumNavigation(
                                          entityType.DisplayName(),
                                          navigation.Name,
                                          navigation.GetTargetType().DisplayName(),
                                          navigation.ForeignKey.Properties.Format()));
                        }
                    }

                    if (identityMap == null)
                    {
                        if (!identityMaps.TryGetValue(key, out identityMap))
                        {
                            identityMap       = key.GetIdentityMapFactory()(sensitiveDataLogged);
                            identityMaps[key] = identityMap;
                        }
                    }

                    var entry = identityMap.TryGetEntry(keyValues);
                    if (entry != null)
                    {
                        if (sensitiveDataLogged)
                        {
                            throw new InvalidOperationException(
                                      CoreStrings.SeedDatumDuplicateSensitive(
                                          entityType.DisplayName(), string.Join(", ", key.Properties.Select((p, i) => p.Name + ":" + keyValues[i]))));
                        }

                        throw new InvalidOperationException(
                                  CoreStrings.SeedDatumDuplicate(
                                      entityType.DisplayName(), key.Properties.Format()));
                    }

                    entry = new InternalShadowEntityEntry(null, entityType);

                    identityMap.Add(keyValues, entry);
                }
            }
        }