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

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

                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(), 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;
                }
            }
        }
예제 #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 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() == true &&
                    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;
                }
            }
        }
예제 #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 ValidateKeys(
            [NotNull] IModel model,
            [NotNull] 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));
                    }
                }
            }
        }