diff --git a/src/EFCore.Abstractions/Properties/AbstractionsStrings.Designer.cs b/src/EFCore.Abstractions/Properties/AbstractionsStrings.Designer.cs
index 24e8ce10ae1..45d990e16fe 100644
--- a/src/EFCore.Abstractions/Properties/AbstractionsStrings.Designer.cs
+++ b/src/EFCore.Abstractions/Properties/AbstractionsStrings.Designer.cs
@@ -1,9 +1,6 @@
//
-using System;
-using System.Reflection;
using System.Resources;
-using JetBrains.Annotations;
#nullable enable
diff --git a/src/EFCore.Cosmos/Design/Internal/CosmosCSharpRuntimeAnnotationCodeGenerator.cs b/src/EFCore.Cosmos/Design/Internal/CosmosCSharpRuntimeAnnotationCodeGenerator.cs
new file mode 100644
index 00000000000..5904acbfc37
--- /dev/null
+++ b/src/EFCore.Cosmos/Design/Internal/CosmosCSharpRuntimeAnnotationCodeGenerator.cs
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;
+using Microsoft.EntityFrameworkCore.Design.Internal;
+using Microsoft.EntityFrameworkCore.Metadata;
+
+namespace Microsoft.EntityFrameworkCore.Cosmos.Design.Internal
+{
+ ///
+ /// 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.
+ ///
+#pragma warning disable EF1001 // Internal EF Core API usage.
+ public class CosmosCSharpRuntimeAnnotationCodeGenerator : CSharpRuntimeAnnotationCodeGenerator
+ {
+ ///
+ /// 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.
+ ///
+ public CosmosCSharpRuntimeAnnotationCodeGenerator(
+ CSharpRuntimeAnnotationCodeGeneratorDependencies dependencies)
+ : base(dependencies)
+ {
+ }
+
+ ///
+ public override void Generate(IModel model, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
+ {
+ var annotations = parameters.Annotations;
+ if (!parameters.IsRuntime)
+ {
+ annotations.Remove(CosmosAnnotationNames.Throughput);
+ }
+
+ base.Generate(model, parameters);
+ }
+
+ ///
+ public override void Generate(IEntityType entityType, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
+ {
+ var annotations = parameters.Annotations;
+ if (!parameters.IsRuntime)
+ {
+ annotations.Remove(CosmosAnnotationNames.AnalyticalStoreTimeToLive);
+ annotations.Remove(CosmosAnnotationNames.DefaultTimeToLive);
+ annotations.Remove(CosmosAnnotationNames.Throughput);
+ }
+
+ base.Generate(entityType, parameters);
+ }
+ }
+}
diff --git a/src/EFCore.Cosmos/Design/Internal/CosmosDesignTimeServices.cs b/src/EFCore.Cosmos/Design/Internal/CosmosDesignTimeServices.cs
index 1dd9203dea5..9c72b13aa09 100644
--- a/src/EFCore.Cosmos/Design/Internal/CosmosDesignTimeServices.cs
+++ b/src/EFCore.Cosmos/Design/Internal/CosmosDesignTimeServices.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.EntityFrameworkCore.Design;
+using Microsoft.EntityFrameworkCore.Design.Internal;
using Microsoft.Extensions.DependencyInjection;
[assembly: DesignTimeProviderServices("Microsoft.EntityFrameworkCore.Cosmos.Design.Internal.CosmosDesignTimeServices")]
@@ -25,7 +26,10 @@ public class CosmosDesignTimeServices : IDesignTimeServices
public virtual void ConfigureDesignTimeServices(IServiceCollection serviceCollection)
{
serviceCollection.AddEntityFrameworkCosmos();
+#pragma warning disable EF1001 // Internal EF Core API usage.
new EntityFrameworkDesignServicesBuilder(serviceCollection)
+ .TryAdd()
+#pragma warning restore EF1001 // Internal EF Core API usage.
.TryAddCoreServices();
}
}
diff --git a/src/EFCore.Cosmos/Extensions/CosmosEntityTypeBuilderExtensions.cs b/src/EFCore.Cosmos/Extensions/CosmosEntityTypeBuilderExtensions.cs
index a6aafb041ad..7e92cde073d 100644
--- a/src/EFCore.Cosmos/Extensions/CosmosEntityTypeBuilderExtensions.cs
+++ b/src/EFCore.Cosmos/Extensions/CosmosEntityTypeBuilderExtensions.cs
@@ -4,8 +4,10 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
+using Microsoft.Azure.Cosmos;
using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Utilities;
@@ -288,5 +290,258 @@ public static EntityTypeBuilder UseETagConcurrency(this Entity
UseETagConcurrency((EntityTypeBuilder)entityTypeBuilder);
return entityTypeBuilder;
}
+
+ ///
+ /// Configures the time to live for analytical store in seconds at container scope.
+ ///
+ /// The builder for the entity type being configured.
+ /// The time to live.
+ /// The same builder instance so that multiple calls can be chained.
+ public static EntityTypeBuilder HasAnalyticalStoreTimeToLive(
+ this EntityTypeBuilder entityTypeBuilder,
+ int? seconds)
+ {
+ entityTypeBuilder.Metadata.SetAnalyticalStoreTimeToLive(seconds);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// Configures the time to live for analytical store in seconds at container scope.
+ ///
+ /// The builder for the entity type being configured.
+ /// The time to live.
+ /// The same builder instance so that multiple calls can be chained.
+ public static EntityTypeBuilder HasAnalyticalStoreTimeToLive(
+ this EntityTypeBuilder entityTypeBuilder,
+ int? seconds)
+ where TEntity : class
+ {
+ entityTypeBuilder.Metadata.SetAnalyticalStoreTimeToLive(seconds);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// Configures the time to live for analytical store in seconds at container scope.
+ ///
+ /// The builder for the entity type being configured.
+ /// The time to live.
+ /// Indicates whether the configuration was specified using a data annotation.
+ ///
+ /// The same builder instance if the configuration was applied,
+ /// otherwise.
+ ///
+ public static IConventionEntityTypeBuilder? HasAnalyticalStoreTimeToLive(
+ this IConventionEntityTypeBuilder entityTypeBuilder,
+ int? seconds,
+ bool fromDataAnnotation = false)
+ {
+ if (!entityTypeBuilder.CanSetAnalyticalStoreTimeToLive(seconds, fromDataAnnotation))
+ {
+ return null;
+ }
+
+ entityTypeBuilder.Metadata.SetAnalyticalStoreTimeToLive(seconds, fromDataAnnotation);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// Returns a value indicating whether the time to live for analytical store can be set
+ /// from the current configuration source
+ ///
+ /// The builder for the entity type being configured.
+ /// The time to live.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// if the configuration can be applied.
+ public static bool CanSetAnalyticalStoreTimeToLive(
+ this IConventionEntityTypeBuilder entityTypeBuilder,
+ int? seconds,
+ bool fromDataAnnotation = false)
+ {
+ Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));
+
+ return entityTypeBuilder.CanSetAnnotation(CosmosAnnotationNames.AnalyticalStoreTimeToLive, seconds, fromDataAnnotation);
+ }
+
+ ///
+ /// Configures the default time to live in seconds at container scope.
+ ///
+ /// The builder for the entity type being configured.
+ /// The time to live.
+ /// The same builder instance so that multiple calls can be chained.
+ public static EntityTypeBuilder HasDefaultTimeToLive(
+ this EntityTypeBuilder entityTypeBuilder,
+ int? seconds)
+ {
+ entityTypeBuilder.Metadata.SetDefaultTimeToLive(seconds);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// Configures the default time to live in seconds at container scope.
+ ///
+ /// The builder for the entity type being configured.
+ /// The time to live.
+ /// The same builder instance so that multiple calls can be chained.
+ public static EntityTypeBuilder HasDefaultTimeToLive(
+ this EntityTypeBuilder entityTypeBuilder,
+ int? seconds)
+ where TEntity : class
+ {
+ entityTypeBuilder.Metadata.SetDefaultTimeToLive(seconds);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// Configures the default time to live in seconds at container scope.
+ ///
+ /// The builder for the entity type being configured.
+ /// The time to live.
+ /// Indicates whether the configuration was specified using a data annotation.
+ ///
+ /// The same builder instance if the configuration was applied,
+ /// otherwise.
+ ///
+ public static IConventionEntityTypeBuilder? HasDefaultTimeToLive(
+ this IConventionEntityTypeBuilder entityTypeBuilder,
+ int? seconds,
+ bool fromDataAnnotation = false)
+ {
+ if (!entityTypeBuilder.CanSetDefaultTimeToLive(seconds, fromDataAnnotation))
+ {
+ return null;
+ }
+
+ entityTypeBuilder.Metadata.SetDefaultTimeToLive(seconds, fromDataAnnotation);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// Returns a value indicating whether the default time to live can be set
+ /// from the current configuration source
+ ///
+ /// The builder for the entity type being configured.
+ /// The time to live.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// if the configuration can be applied.
+ public static bool CanSetDefaultTimeToLive(
+ this IConventionEntityTypeBuilder entityTypeBuilder,
+ int? seconds,
+ bool fromDataAnnotation = false)
+ {
+ Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));
+
+ return entityTypeBuilder.CanSetAnnotation(CosmosAnnotationNames.DefaultTimeToLive, seconds, fromDataAnnotation);
+ }
+
+ ///
+ /// Configures the manual provisioned throughput offering.
+ ///
+ /// The builder for the entity type being configured.
+ /// The throughput to set.
+ public static EntityTypeBuilder HasManualThroughput(this EntityTypeBuilder entityTypeBuilder, int? throughput)
+ {
+ entityTypeBuilder.Metadata.SetThroughput(throughput, autoscale: false);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// Configures the manual provisioned throughput offering.
+ ///
+ /// The builder for the entity type being configured.
+ /// The throughput to set.
+ public static EntityTypeBuilder HasManualThroughput(this EntityTypeBuilder entityTypeBuilder, int? throughput)
+ where TEntity : class
+ {
+ entityTypeBuilder.Metadata.SetThroughput(throughput, autoscale: false);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// Configures the autoscale provisioned throughput offering.
+ ///
+ /// The builder for the entity type being configured.
+ /// The throughput to set.
+ public static EntityTypeBuilder HasAutoscaleThroughput(this EntityTypeBuilder entityTypeBuilder, int? throughput)
+ {
+ entityTypeBuilder.Metadata.SetThroughput(throughput, autoscale: true);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// Configures the autoscale provisioned throughput offering.
+ ///
+ /// The builder for the entity type being configured.
+ /// The throughput to set.
+ public static EntityTypeBuilder HasAutoscaleThroughput(this EntityTypeBuilder entityTypeBuilder, int? throughput)
+ where TEntity : class
+ {
+ entityTypeBuilder.Metadata.SetThroughput(throughput, autoscale: true);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// Configures the provisioned throughput.
+ ///
+ /// The builder for the entity type being configured.
+ /// The throughput to set.
+ /// Whether autoscale is enabled.
+ /// Indicates whether the configuration was specified using a data annotation.
+ public static IConventionEntityTypeBuilder? HasThroughput(
+ this IConventionEntityTypeBuilder entityTypeBuilder,
+ int? throughput,
+ bool autoscale,
+ bool fromDataAnnotation = false)
+ {
+ if (!entityTypeBuilder.CanSetThroughput(throughput, autoscale, fromDataAnnotation))
+ {
+ return null;
+ }
+
+ entityTypeBuilder.Metadata.SetThroughput(throughput, autoscale, fromDataAnnotation);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// Returns a value indicating whether the given throughput can be set.
+ ///
+ /// The builder for the entity type being configured.
+ /// The throughput to set.
+ /// Whether autoscale is enabled.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// if the given container name can be set as default.
+ public static bool CanSetThroughput(
+ this IConventionEntityTypeBuilder entityTypeBuilder,
+ int? throughput,
+ bool autoscale,
+ bool fromDataAnnotation = false)
+ {
+ var existingAnnotation = entityTypeBuilder.Metadata.FindAnnotation(CosmosAnnotationNames.Throughput);
+ if (existingAnnotation == null)
+ {
+ return true;
+ }
+
+ var configurationSource = fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention;
+ if (configurationSource.Overrides(existingAnnotation.GetConfigurationSource()))
+ {
+ return true;
+ }
+
+ var existingThroughput = (ThroughputProperties?)existingAnnotation.Value;
+ return autoscale
+ ? existingThroughput?.Throughput == throughput
+ : existingThroughput?.AutoscaleMaxThroughput == throughput;
+ }
}
}
diff --git a/src/EFCore.Cosmos/Extensions/CosmosEntityTypeExtensions.cs b/src/EFCore.Cosmos/Extensions/CosmosEntityTypeExtensions.cs
index cb5f588e2e8..e9125995a27 100644
--- a/src/EFCore.Cosmos/Extensions/CosmosEntityTypeExtensions.cs
+++ b/src/EFCore.Cosmos/Extensions/CosmosEntityTypeExtensions.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using Microsoft.Azure.Cosmos;
using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Utilities;
@@ -215,5 +216,148 @@ public static void SetETagPropertyName(
/// The property mapped to etag, or if no property is mapped to ETag.
public static IProperty? GetETagProperty(this IEntityType entityType)
=> (IProperty?)((IReadOnlyEntityType)entityType).GetETagProperty();
+
+ ///
+ /// Returns the time to live for analytical store in seconds at container scope.
+ ///
+ /// The entity type.
+ /// The time to live.
+ public static int? GetAnalyticalStoreTimeToLive(this IReadOnlyEntityType entityType)
+ => entityType.BaseType != null
+ ? entityType.GetRootType().GetAnalyticalStoreTimeToLive()
+ : (int?)entityType[CosmosAnnotationNames.AnalyticalStoreTimeToLive];
+
+ ///
+ /// Sets the time to live for analytical store in seconds at container scope.
+ ///
+ /// The entity type.
+ /// The time to live to set.
+ public static void SetAnalyticalStoreTimeToLive(this IMutableEntityType entityType, int? seconds)
+ => entityType.SetOrRemoveAnnotation(
+ CosmosAnnotationNames.AnalyticalStoreTimeToLive,
+ seconds);
+
+ ///
+ /// Sets the time to live for analytical store in seconds at container scope.
+ ///
+ /// The entity type.
+ /// The time to live to set.
+ /// Indicates whether the configuration was specified using a data annotation.
+ public static void SetAnalyticalStoreTimeToLive(
+ this IConventionEntityType entityType,
+ int? seconds,
+ bool fromDataAnnotation = false)
+ => entityType.SetOrRemoveAnnotation(
+ CosmosAnnotationNames.AnalyticalStoreTimeToLive,
+ seconds,
+ fromDataAnnotation);
+
+ ///
+ /// Gets the for the time to live for analytical store in seconds at container scope.
+ ///
+ /// The entity typer.
+ /// The for the time to live for analytical store.
+ public static ConfigurationSource? GetAnalyticalStoreTimeToLiveConfigurationSource(this IConventionEntityType entityType)
+ => entityType.FindAnnotation(CosmosAnnotationNames.AnalyticalStoreTimeToLive)
+ ?.GetConfigurationSource();
+
+ ///
+ /// Returns the default time to live in seconds at container scope.
+ ///
+ /// The entity type.
+ /// The time to live.
+ public static int? GetDefaultTimeToLive(this IReadOnlyEntityType entityType)
+ => entityType.BaseType != null
+ ? entityType.GetRootType().GetDefaultTimeToLive()
+ : (int?)entityType[CosmosAnnotationNames.DefaultTimeToLive];
+
+ ///
+ /// Sets the default time to live in seconds at container scope.
+ ///
+ /// The entity type.
+ /// The time to live to set.
+ public static void SetDefaultTimeToLive(this IMutableEntityType entityType, int? seconds)
+ => entityType.SetOrRemoveAnnotation(
+ CosmosAnnotationNames.DefaultTimeToLive,
+ seconds);
+
+ ///
+ /// Sets the default time to live in seconds at container scope.
+ ///
+ /// The entity type.
+ /// The time to live to set.
+ /// Indicates whether the configuration was specified using a data annotation.
+ public static void SetDefaultTimeToLive(
+ this IConventionEntityType entityType,
+ int? seconds,
+ bool fromDataAnnotation = false)
+ => entityType.SetOrRemoveAnnotation(
+ CosmosAnnotationNames.DefaultTimeToLive,
+ seconds,
+ fromDataAnnotation);
+
+ ///
+ /// Gets the for the default time to live in seconds at container scope.
+ ///
+ /// The entity type to find configuration source for.
+ /// The for the default time to live.
+ public static ConfigurationSource? GetDefaultTimeToLiveConfigurationSource(this IConventionEntityType entityType)
+ => entityType.FindAnnotation(CosmosAnnotationNames.DefaultTimeToLive)
+ ?.GetConfigurationSource();
+
+ ///
+ /// Returns the provisioned throughput at container scope.
+ ///
+ /// The entity type.
+ /// The throughput.
+ public static ThroughputProperties? GetThroughput(this IReadOnlyEntityType entityType)
+ => entityType.BaseType != null
+ ? entityType.GetRootType().GetThroughput()
+ : (ThroughputProperties?)entityType[CosmosAnnotationNames.Throughput];
+
+ ///
+ /// Sets the provisioned throughput at container scope.
+ ///
+ /// The entity type.
+ /// The throughput to set.
+ /// Whether autoscale is enabled.
+ public static void SetThroughput(this IMutableEntityType entityType, int? throughput, bool? autoscale)
+ => entityType.SetOrRemoveAnnotation(
+ CosmosAnnotationNames.Throughput,
+ throughput == null || autoscale == null
+ ? null
+ : autoscale.Value
+ ? ThroughputProperties.CreateAutoscaleThroughput(throughput.Value)
+ : ThroughputProperties.CreateManualThroughput(throughput.Value));
+
+ ///
+ /// Sets the provisioned throughput at container scope.
+ ///
+ /// The entity type.
+ /// The throughput to set.
+ /// Whether autoscale is enabled.
+ /// Indicates whether the configuration was specified using a data annotation.
+ public static void SetThroughput(
+ this IConventionEntityType entityType,
+ int? throughput,
+ bool? autoscale,
+ bool fromDataAnnotation = false)
+ => entityType.SetOrRemoveAnnotation(
+ CosmosAnnotationNames.Throughput,
+ throughput == null || autoscale == null
+ ? null
+ : autoscale.Value
+ ? ThroughputProperties.CreateAutoscaleThroughput(throughput.Value)
+ : ThroughputProperties.CreateManualThroughput(throughput.Value),
+ fromDataAnnotation);
+
+ ///
+ /// Gets the for the provisioned throughput at container scope.
+ ///
+ /// The entity type to find configuration source for.
+ /// The for the throughput.
+ public static ConfigurationSource? GetThroughputConfigurationSource(this IConventionEntityType entityType)
+ => entityType.FindAnnotation(CosmosAnnotationNames.Throughput)
+ ?.GetConfigurationSource();
}
}
diff --git a/src/EFCore.Cosmos/Extensions/CosmosModelBuilderExtensions.cs b/src/EFCore.Cosmos/Extensions/CosmosModelBuilderExtensions.cs
index 6a2cff5897e..029958b5015 100644
--- a/src/EFCore.Cosmos/Extensions/CosmosModelBuilderExtensions.cs
+++ b/src/EFCore.Cosmos/Extensions/CosmosModelBuilderExtensions.cs
@@ -1,9 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using Microsoft.Azure.Cosmos;
using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;
+using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Utilities;
+using Newtonsoft.Json.Linq;
// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore
@@ -70,10 +73,88 @@ public static bool CanSetDefaultContainer(
string? name,
bool fromDataAnnotation = false)
{
- Check.NotNull(modelBuilder, nameof(modelBuilder));
Check.NullButNotEmpty(name, nameof(name));
return modelBuilder.CanSetAnnotation(CosmosAnnotationNames.ContainerName, name, fromDataAnnotation);
}
+
+ ///
+ /// Configures the manual provisioned throughput offering.
+ ///
+ /// The model builder.
+ /// The throughput to set.
+ public static ModelBuilder HasManualThroughput(this ModelBuilder modelBuilder, int? throughput)
+ {
+ modelBuilder.Model.SetThroughput(throughput, autoscale: false);
+
+ return modelBuilder;
+ }
+
+ ///
+ /// Configures the autoscale provisioned throughput offering.
+ ///
+ /// The model builder.
+ /// The throughput to set.
+ public static ModelBuilder HasAutoscaleThroughput(this ModelBuilder modelBuilder, int? throughput)
+ {
+ modelBuilder.Model.SetThroughput(throughput, autoscale: true);
+
+ return modelBuilder;
+ }
+
+ ///
+ /// Configures the provisioned throughput.
+ ///
+ /// The model builder.
+ /// The throughput to set.
+ /// Whether autoscale is enabled.
+ /// Indicates whether the configuration was specified using a data annotation.
+ public static IConventionModelBuilder? HasThroughput(
+ this IConventionModelBuilder modelBuilder,
+ int? throughput,
+ bool autoscale,
+ bool fromDataAnnotation = false)
+ {
+ if (!modelBuilder.CanSetThroughput(throughput, autoscale, fromDataAnnotation))
+ {
+ return null;
+ }
+
+ modelBuilder.Metadata.SetThroughput(throughput, autoscale, fromDataAnnotation);
+
+ return modelBuilder;
+ }
+
+ ///
+ /// Returns a value indicating whether the given throughput can be set.
+ ///
+ /// The model builder.
+ /// The throughput to set.
+ /// Whether autoscale is enabled.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// if the given container name can be set as default.
+ public static bool CanSetThroughput(
+ this IConventionModelBuilder modelBuilder,
+ int? throughput,
+ bool autoscale,
+ bool fromDataAnnotation = false)
+ {
+ var existingAnnotation = modelBuilder.Metadata.FindAnnotation(CosmosAnnotationNames.Throughput);
+ if (existingAnnotation == null)
+ {
+ return true;
+ }
+
+ var configurationSource = fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention;
+ if (configurationSource.Overrides(existingAnnotation.GetConfigurationSource()))
+ {
+ return true;
+ }
+
+ var existingThroughput = (ThroughputProperties?)existingAnnotation.Value;
+ return autoscale
+ ? existingThroughput?.Throughput == throughput
+ : existingThroughput?.AutoscaleMaxThroughput == throughput;
+ }
}
}
diff --git a/src/EFCore.Cosmos/Extensions/CosmosModelExtensions.cs b/src/EFCore.Cosmos/Extensions/CosmosModelExtensions.cs
index 65f0f89693a..a5bdb09902b 100644
--- a/src/EFCore.Cosmos/Extensions/CosmosModelExtensions.cs
+++ b/src/EFCore.Cosmos/Extensions/CosmosModelExtensions.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using Microsoft.Azure.Cosmos;
using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Utilities;
@@ -58,5 +59,61 @@ public static void SetDefaultContainer(this IMutableModel model, string? name)
/// The configuration source for the default container name.
public static ConfigurationSource? GetDefaultContainerConfigurationSource(this IConventionModel model)
=> model.FindAnnotation(CosmosAnnotationNames.ContainerName)?.GetConfigurationSource();
+
+ ///
+ /// Returns the provisioned throughput at database scope.
+ ///
+ /// The model.
+ /// The throughput.
+ public static ThroughputProperties? GetThroughput(this IReadOnlyModel model)
+ => (ThroughputProperties?)model[CosmosAnnotationNames.Throughput];
+
+ ///
+ /// Sets the provisioned throughput at database scope.
+ ///
+ /// The model.
+ /// The throughput to set.
+ /// Whether autoscale is enabled.
+ public static void SetThroughput(this IMutableModel model, int? throughput, bool? autoscale)
+ => model.SetOrRemoveAnnotation(
+ CosmosAnnotationNames.Throughput,
+ throughput == null || autoscale == null
+ ? null
+ : autoscale.Value
+ ? ThroughputProperties.CreateAutoscaleThroughput(throughput.Value)
+ : ThroughputProperties.CreateManualThroughput(throughput.Value));
+
+ ///
+ /// Sets the provisioned throughput at database scope.
+ ///
+ /// The model.
+ /// The throughput to set.
+ /// Whether autoscale is enabled.
+ /// Indicates whether the configuration was specified using a data annotation.
+ public static int? SetThroughput(
+ this IConventionModel model,
+ int? throughput,
+ bool? autoscale,
+ bool fromDataAnnotation = false)
+ {
+ var valueSet = (ThroughputProperties?)model.SetOrRemoveAnnotation(
+ CosmosAnnotationNames.Throughput,
+ throughput == null || autoscale == null
+ ? null
+ : autoscale.Value
+ ? ThroughputProperties.CreateAutoscaleThroughput(throughput.Value)
+ : ThroughputProperties.CreateManualThroughput(throughput.Value),
+ fromDataAnnotation)?.Value;
+ return valueSet?.AutoscaleMaxThroughput ?? valueSet?.Throughput;
+ }
+
+ ///
+ /// Gets the for the provisioned throughput at database scope.
+ ///
+ /// The model.
+ /// The for the throughput.
+ public static ConfigurationSource? GetThroughputConfigurationSource(this IConventionModel model)
+ => model.FindAnnotation(CosmosAnnotationNames.Throughput)
+ ?.GetConfigurationSource();
}
}
diff --git a/src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs b/src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs
index feae50c3492..e74a263fd20 100644
--- a/src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs
+++ b/src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs
@@ -1,9 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.Collections.Generic;
-using System.Linq;
+using Microsoft.Azure.Cosmos;
using Microsoft.EntityFrameworkCore.Cosmos.Internal;
using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Diagnostics;
@@ -98,6 +96,9 @@ protected virtual void ValidateSharedContainerCompatibility(
{
var discriminatorValues = new Dictionary