/// <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 ValidateKeys( IModel model, IDiagnosticsLogger <DbLoggerCategory.Model.Validation> logger) { foreach (var entityType in model.GetEntityTypes()) { var primaryKey = entityType.FindPrimaryKey(); if (primaryKey == null || !entityType.IsDocumentRoot()) { continue; } var idProperty = entityType.GetProperties() .FirstOrDefault(p => p.GetJsonPropertyName() == StoreKeyConvention.IdPropertyJsonName); if (idProperty == null) { throw new InvalidOperationException(CosmosStrings.NoIdProperty(entityType.DisplayName())); } var idType = idProperty.GetTypeMapping().Converter?.ProviderClrType ?? idProperty.ClrType; if (idType != typeof(string)) { throw new InvalidOperationException( CosmosStrings.IdNonStringStoreType( idProperty.Name, entityType.DisplayName(), idType.ShortDisplayName())); } if (!idProperty.IsKey()) { throw new InvalidOperationException(CosmosStrings.NoIdKey(entityType.DisplayName(), idProperty.Name)); } var partitionKeyPropertyName = entityType.GetPartitionKeyPropertyName(); if (partitionKeyPropertyName != null) { var partitionKey = entityType.FindProperty(partitionKeyPropertyName); if (partitionKey == null) { throw new InvalidOperationException( CosmosStrings.PartitionKeyMissingProperty(entityType.DisplayName(), partitionKeyPropertyName)); } var partitionKeyType = partitionKey.GetTypeMapping().Converter?.ProviderClrType ?? partitionKey.ClrType; if (partitionKeyType != typeof(string)) { throw new InvalidOperationException( CosmosStrings.PartitionKeyNonStringStoreType( partitionKeyPropertyName, entityType.DisplayName(), partitionKeyType.ShortDisplayName())); } if (!partitionKey.GetContainingKeys().Any(k => k.Properties.Contains(idProperty))) { throw new InvalidOperationException( CosmosStrings.NoPartitionKeyKey( entityType.DisplayName(), partitionKeyPropertyName, idProperty.Name)); } } } }
/// <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) { 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)); } var keyType = nextPartitionKeyProperty.GetTypeMapping().Converter?.ProviderClrType ?? nextPartitionKeyProperty.ClrType; if (keyType != typeof(string)) { throw new InvalidOperationException(CosmosStrings.PartitionKeyNonStringStoreType( partitionKeyPropertyName, entityType.DisplayName(), keyType.ShortDisplayName())); } 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 != null) { throw new InvalidOperationException(CosmosStrings.NoPartitionKey(entityType.DisplayName(), containerName)); } if (mappedTypes.Count == 1) { break; } if (firstEntityType == null) { firstEntityType = entityType; } if (entityType.ClrType?.IsInstantiable() == true && entityType.GetCosmosContainingPropertyName() == null) { 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; } } }