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