public virtual void Detects_duplicate_discriminator_values() { var modelBuilder = CreateConventionalModelBuilder(); modelBuilder.Entity <Customer>().ToContainer("Orders").HasDiscriminator().HasValue("type"); modelBuilder.Entity <Order>().ToContainer("Orders").HasDiscriminator().HasValue("type"); VerifyError(CosmosStrings.DuplicateDiscriminatorValue(typeof(Order).Name, "type", typeof(Customer).Name, "Orders"), modelBuilder); }
/// <summary> /// Validates the compatibility of entity types sharing a given container. /// </summary> /// <param name="mappedTypes"> The mapped entity types. </param> /// <param name="containerName"> The container name. </param> /// <param name="logger"> The logger to use. </param> protected virtual void ValidateSharedContainerCompatibility( [NotNull] IReadOnlyList <IEntityType> mappedTypes, [NotNull] string containerName, [NotNull] IDiagnosticsLogger <DbLoggerCategory.Model.Validation> logger) { if (mappedTypes.Count == 1) { var entityType = mappedTypes[0]; var partitionKeyPropertyName = entityType.GetCosmosPartitionKeyPropertyName(); if (partitionKeyPropertyName != null) { var nextPartitionKeyProperty = entityType.FindProperty(partitionKeyPropertyName); if (nextPartitionKeyProperty == null) { throw new InvalidOperationException( CosmosStrings.PartitionKeyMissingProperty(entityType.DisplayName(), partitionKeyPropertyName)); } } return; } var discriminatorValues = new Dictionary <object, IEntityType>(); IProperty partitionKey = null; IEntityType firstEntityType = null; foreach (var entityType in mappedTypes) { var partitionKeyPropertyName = entityType.GetCosmosPartitionKeyPropertyName(); if (partitionKeyPropertyName != null) { var nextPartitionKeyProperty = entityType.FindProperty(partitionKeyPropertyName); if (nextPartitionKeyProperty == null) { throw new InvalidOperationException( CosmosStrings.PartitionKeyMissingProperty(entityType.DisplayName(), partitionKeyPropertyName)); } if (partitionKey == null) { if (firstEntityType != null) { throw new InvalidOperationException(CosmosStrings.NoPartitionKey(firstEntityType.DisplayName(), containerName)); } partitionKey = nextPartitionKeyProperty; } else if (partitionKey.GetCosmosPropertyName() != nextPartitionKeyProperty.GetCosmosPropertyName()) { throw new InvalidOperationException( CosmosStrings.PartitionKeyStoreNameMismatch( partitionKey.Name, firstEntityType.DisplayName(), partitionKey.GetCosmosPropertyName(), nextPartitionKeyProperty.Name, entityType.DisplayName(), nextPartitionKeyProperty.GetCosmosPropertyName())); } else if ((partitionKey.GetTypeMapping().Converter?.ProviderClrType ?? partitionKey.ClrType) != (nextPartitionKeyProperty.GetTypeMapping().Converter?.ProviderClrType ?? nextPartitionKeyProperty.ClrType)) { throw new InvalidOperationException( CosmosStrings.PartitionKeyStoreTypeMismatch( partitionKey.Name, firstEntityType.DisplayName(), (partitionKey.GetTypeMapping().Converter?.ProviderClrType ?? partitionKey.ClrType).ShortDisplayName(), nextPartitionKeyProperty.Name, entityType.DisplayName(), (nextPartitionKeyProperty.GetTypeMapping().Converter?.ProviderClrType ?? nextPartitionKeyProperty.ClrType) .ShortDisplayName())); } } else if (partitionKey != null) { throw new InvalidOperationException(CosmosStrings.NoPartitionKey(entityType.DisplayName(), containerName)); } if (firstEntityType == null) { firstEntityType = entityType; } if (entityType.ClrType?.IsInstantiable() == true) { if (entityType.GetDiscriminatorProperty() == null) { throw new InvalidOperationException( CosmosStrings.NoDiscriminatorProperty(entityType.DisplayName(), containerName)); } var discriminatorValue = entityType.GetDiscriminatorValue(); if (discriminatorValue == null) { throw new InvalidOperationException( CosmosStrings.NoDiscriminatorValue(entityType.DisplayName(), containerName)); } if (discriminatorValues.TryGetValue(discriminatorValue, out var duplicateEntityType)) { throw new InvalidOperationException( CosmosStrings.DuplicateDiscriminatorValue( entityType.DisplayName(), discriminatorValue, duplicateEntityType.DisplayName(), containerName)); } discriminatorValues[discriminatorValue] = entityType; } } }
/// <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 ValidateSharedContainerCompatibility( [NotNull] IReadOnlyList <IEntityType> mappedTypes, [NotNull] string container, [NotNull] IDiagnosticsLogger <DbLoggerCategory.Model.Validation> logger) { var discriminatorValues = new Dictionary <object, IEntityType>(); IProperty partitionKey = null; IEntityType firstEntityType = null; foreach (var entityType in mappedTypes) { Check.DebugAssert(entityType.IsDocumentRoot(), "Only document roots expected here."); var partitionKeyPropertyName = entityType.GetPartitionKeyPropertyName(); if (partitionKeyPropertyName != null) { var nextPartitionKeyProperty = entityType.FindProperty(partitionKeyPropertyName); if (partitionKey == null) { if (firstEntityType != null) { throw new InvalidOperationException(CosmosStrings.NoPartitionKey(firstEntityType.DisplayName(), container)); } partitionKey = nextPartitionKeyProperty; } else if (partitionKey.GetJsonPropertyName() != nextPartitionKeyProperty.GetJsonPropertyName()) { throw new InvalidOperationException( CosmosStrings.PartitionKeyStoreNameMismatch( partitionKey.Name, firstEntityType.DisplayName(), partitionKey.GetJsonPropertyName(), nextPartitionKeyProperty.Name, entityType.DisplayName(), nextPartitionKeyProperty.GetJsonPropertyName())); } } else if (partitionKey != null) { throw new InvalidOperationException(CosmosStrings.NoPartitionKey(entityType.DisplayName(), container)); } if (mappedTypes.Count == 1) { break; } if (firstEntityType == null) { firstEntityType = entityType; } if (entityType.ClrType.IsInstantiable() && entityType.GetContainingPropertyName() == null) { if (entityType.GetDiscriminatorProperty() == null) { throw new InvalidOperationException( CosmosStrings.NoDiscriminatorProperty(entityType.DisplayName(), container)); } var discriminatorValue = entityType.GetDiscriminatorValue(); if (discriminatorValue == null) { throw new InvalidOperationException( CosmosStrings.NoDiscriminatorValue(entityType.DisplayName(), container)); } if (discriminatorValues.TryGetValue(discriminatorValue, out var duplicateEntityType)) { throw new InvalidOperationException( CosmosStrings.DuplicateDiscriminatorValue( entityType.DisplayName(), discriminatorValue, duplicateEntityType.DisplayName(), container)); } discriminatorValues[discriminatorValue] = entityType; } } }
/// <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 ValidateSharedContainerCompatibility( IReadOnlyList <IEntityType> mappedTypes, string container, IDiagnosticsLogger <DbLoggerCategory.Model.Validation> logger) { var discriminatorValues = new Dictionary <object, IEntityType>(); IProperty? partitionKey = null; int? analyticalTTL = null; int? defaultTTL = null; ThroughputProperties?throughput = null; IEntityType? firstEntityType = null; foreach (var entityType in mappedTypes) { Check.DebugAssert(entityType.IsDocumentRoot(), "Only document roots expected here."); var partitionKeyPropertyName = entityType.GetPartitionKeyPropertyName(); if (partitionKeyPropertyName != null) { var nextPartitionKeyProperty = entityType.FindProperty(partitionKeyPropertyName) !; if (partitionKey == null) { if (firstEntityType != null) { throw new InvalidOperationException(CosmosStrings.NoPartitionKey(firstEntityType.DisplayName(), container)); } partitionKey = nextPartitionKeyProperty; } else if (partitionKey.GetJsonPropertyName() != nextPartitionKeyProperty.GetJsonPropertyName()) { throw new InvalidOperationException( CosmosStrings.PartitionKeyStoreNameMismatch( partitionKey.Name, firstEntityType !.DisplayName(), partitionKey.GetJsonPropertyName(), nextPartitionKeyProperty.Name, entityType.DisplayName(), nextPartitionKeyProperty.GetJsonPropertyName())); } } else if (partitionKey != null) { throw new InvalidOperationException(CosmosStrings.NoPartitionKey(entityType.DisplayName(), container)); } if (mappedTypes.Count == 1) { break; } if (firstEntityType == null) { firstEntityType = entityType; } if (entityType.ClrType.IsInstantiable() && entityType.GetContainingPropertyName() == null) { if (entityType.FindDiscriminatorProperty() == null) { throw new InvalidOperationException( CosmosStrings.NoDiscriminatorProperty(entityType.DisplayName(), container)); } var discriminatorValue = entityType.GetDiscriminatorValue(); if (discriminatorValue == null) { throw new InvalidOperationException( CosmosStrings.NoDiscriminatorValue(entityType.DisplayName(), container)); } if (discriminatorValues.TryGetValue(discriminatorValue, out var duplicateEntityType)) { throw new InvalidOperationException( CosmosStrings.DuplicateDiscriminatorValue( entityType.DisplayName(), discriminatorValue, duplicateEntityType.DisplayName(), container)); } discriminatorValues[discriminatorValue] = entityType; } var currentAnalyticalTTL = entityType.GetAnalyticalStoreTimeToLive(); if (currentAnalyticalTTL != null) { if (analyticalTTL == null) { analyticalTTL = currentAnalyticalTTL; } else if (analyticalTTL != currentAnalyticalTTL) { var conflictingEntityType = mappedTypes.First(et => et.GetAnalyticalStoreTimeToLive() != null); throw new InvalidOperationException( CosmosStrings.AnalyticalTTLMismatch( analyticalTTL, conflictingEntityType.DisplayName(), entityType.DisplayName(), currentAnalyticalTTL, container)); } } var currentDefaultTTL = entityType.GetDefaultTimeToLive(); if (currentDefaultTTL != null) { if (defaultTTL == null) { defaultTTL = currentDefaultTTL; } else if (defaultTTL != currentDefaultTTL) { var conflictingEntityType = mappedTypes.First(et => et.GetDefaultTimeToLive() != null); throw new InvalidOperationException( CosmosStrings.DefaultTTLMismatch( defaultTTL, conflictingEntityType.DisplayName(), entityType.DisplayName(), currentDefaultTTL, container)); } } var currentThroughput = entityType.GetThroughput(); if (currentThroughput != null) { if (throughput == null) { throughput = currentThroughput; } else if ((throughput.AutoscaleMaxThroughput ?? throughput.Throughput) != (currentThroughput.AutoscaleMaxThroughput ?? currentThroughput.Throughput)) { var conflictingEntityType = mappedTypes.First(et => et.GetThroughput() != null); throw new InvalidOperationException( CosmosStrings.ThroughputMismatch( throughput.AutoscaleMaxThroughput ?? throughput.Throughput, conflictingEntityType.DisplayName(), entityType.DisplayName(), currentThroughput.AutoscaleMaxThroughput ?? currentThroughput.Throughput, container)); } else if ((throughput.AutoscaleMaxThroughput == null) != (currentThroughput.AutoscaleMaxThroughput == null)) { var conflictingEntityType = mappedTypes.First(et => et.GetThroughput() != null); var autoscaleType = throughput.AutoscaleMaxThroughput == null ? entityType : conflictingEntityType; var manualType = throughput.AutoscaleMaxThroughput != null ? entityType : conflictingEntityType; throw new InvalidOperationException( CosmosStrings.ThroughputTypeMismatch( manualType.DisplayName(), autoscaleType.DisplayName(), container)); } } } }