Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.Scripts;
using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;

// ReSharper disable once CheckNamespace
Expand Down Expand Up @@ -1007,4 +1008,43 @@ public static bool CanSetThroughput(
? existingThroughput?.Throughput == throughput
: existingThroughput?.AutoscaleMaxThroughput == throughput;
}

/// <summary>
/// Configures a database trigger on the entity.
/// </summary>
/// <param name="entityTypeBuilder">The builder for the entity type being configured.</param>
/// <param name="modelName">The name of the trigger.</param>
/// <param name="triggerType">The trigger type.</param>
/// <param name="triggerOperation">The trigger operation.</param>
/// <returns>A builder that can be used to configure the database trigger.</returns>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-triggers">Database triggers</see> for more information and examples.
/// </remarks>
public static TriggerBuilder HasTrigger(this EntityTypeBuilder entityTypeBuilder, string modelName, TriggerType triggerType, TriggerOperation triggerOperation)
{
var triggerBuilder = EntityTypeBuilder.HasTrigger(entityTypeBuilder.Metadata, modelName);
triggerBuilder.Metadata.SetTriggerType(triggerType);
triggerBuilder.Metadata.SetTriggerOperation(triggerOperation);
return triggerBuilder;
}

/// <summary>
/// Configures a database trigger on the entity.
/// </summary>
/// <param name="entityTypeBuilder">The builder for the entity type being configured.</param>
/// <param name="modelName">The name of the trigger.</param>
/// <param name="triggerType">The trigger type.</param>
/// <param name="triggerOperation">The trigger operation.</param>
/// <returns>A builder that can be used to configure the database trigger.</returns>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-triggers">Database triggers</see> for more information and examples.
/// </remarks>
public static TriggerBuilder HasTrigger<TEntity>(this EntityTypeBuilder<TEntity> entityTypeBuilder, string modelName, TriggerType triggerType, TriggerOperation triggerOperation)
where TEntity : class
{
var triggerBuilder = EntityTypeBuilder.HasTrigger(entityTypeBuilder.Metadata, modelName);
triggerBuilder.Metadata.SetTriggerType(triggerType);
triggerBuilder.Metadata.SetTriggerOperation(triggerOperation);
return triggerBuilder;
}
}
92 changes: 92 additions & 0 deletions src/EFCore.Cosmos/Extensions/CosmosTriggerBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// 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.Scripts;
using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;

// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore;

/// <summary>
/// Cosmos DB specific extension methods for <see cref="TriggerBuilder" />.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-triggers">Database triggers</see> for more information and examples.
/// </remarks>
public static class CosmosTriggerBuilderExtensions
{

/// <summary>
/// Configures the Cosmos DB trigger type for this trigger.
/// </summary>
/// <param name="triggerBuilder">The builder for the trigger being configured.</param>
/// <param name="triggerType">The Cosmos DB trigger type.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>
/// The same builder instance if the configuration was applied,
/// <see langword="null" /> otherwise.
/// </returns>
public static IConventionTriggerBuilder? HasTriggerType(
this IConventionTriggerBuilder triggerBuilder,
TriggerType? triggerType,
bool fromDataAnnotation = false)
{
if (!triggerBuilder.CanSetTriggerType(triggerType, fromDataAnnotation))
{
return null;
}

triggerBuilder.Metadata.SetTriggerType(triggerType, fromDataAnnotation);
return triggerBuilder;
}

/// <summary>
/// Returns a value indicating whether the given Cosmos DB trigger type can be set for this trigger.
/// </summary>
/// <param name="triggerBuilder">The builder for the trigger being configured.</param>
/// <param name="triggerType">The Cosmos DB trigger type.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns><see langword="true" /> if the Cosmos DB trigger type can be set for this trigger.</returns>
public static bool CanSetTriggerType(
this IConventionTriggerBuilder triggerBuilder,
TriggerType? triggerType,
bool fromDataAnnotation = false)
=> triggerBuilder.CanSetAnnotation(CosmosAnnotationNames.TriggerType, triggerType, fromDataAnnotation);

/// <summary>
/// Configures the Cosmos DB trigger operation for this trigger.
/// </summary>
/// <param name="triggerBuilder">The builder for the trigger being configured.</param>
/// <param name="triggerOperation">The Cosmos DB trigger operation.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>
/// The same builder instance if the configuration was applied,
/// <see langword="null" /> otherwise.
/// </returns>
public static IConventionTriggerBuilder? HasTriggerOperation(
this IConventionTriggerBuilder triggerBuilder,
TriggerOperation? triggerOperation,
bool fromDataAnnotation = false)
{
if (!triggerBuilder.CanSetTriggerOperation(triggerOperation, fromDataAnnotation))
{
return null;
}

triggerBuilder.Metadata.SetTriggerOperation(triggerOperation, fromDataAnnotation);
return triggerBuilder;
}

/// <summary>
/// Returns a value indicating whether the given Cosmos DB trigger operation can be set for this trigger.
/// </summary>
/// <param name="triggerBuilder">The builder for the trigger being configured.</param>
/// <param name="triggerOperation">The Cosmos DB trigger operation.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns><see langword="true" /> if the Cosmos DB trigger operation can be set for this trigger.</returns>
public static bool CanSetTriggerOperation(
this IConventionTriggerBuilder triggerBuilder,
TriggerOperation? triggerOperation,
bool fromDataAnnotation = false)
=> triggerBuilder.CanSetAnnotation(CosmosAnnotationNames.TriggerOperation, triggerOperation, fromDataAnnotation);
}
91 changes: 91 additions & 0 deletions src/EFCore.Cosmos/Extensions/CosmosTriggerExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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.Scripts;
using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;

// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore;

/// <summary>
/// Cosmos DB specific extension methods for <see cref="ITrigger" /> and related types.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-triggers">Database triggers</see> for more information and examples.
/// </remarks>
public static class CosmosTriggerExtensions
{
/// <summary>
/// Gets the Cosmos DB trigger type for this trigger.
/// </summary>
/// <param name="trigger">The trigger.</param>
/// <returns>The Cosmos DB trigger type.</returns>
public static TriggerType? GetTriggerType(this IReadOnlyTrigger trigger)
=> (TriggerType?)trigger[CosmosAnnotationNames.TriggerType];

/// <summary>
/// Sets the Cosmos DB trigger type for this trigger.
/// </summary>
/// <param name="trigger">The trigger.</param>
/// <param name="triggerType">The Cosmos DB trigger type.</param>
public static void SetTriggerType(this IMutableTrigger trigger, TriggerType? triggerType)
=> trigger.SetOrRemoveAnnotation(CosmosAnnotationNames.TriggerType, triggerType);

/// <summary>
/// Sets the Cosmos DB trigger type for this trigger.
/// </summary>
/// <param name="trigger">The trigger.</param>
/// <param name="triggerType">The Cosmos DB trigger type.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The configured value.</returns>
public static TriggerType? SetTriggerType(
this IConventionTrigger trigger,
TriggerType? triggerType,
bool fromDataAnnotation = false)
=> (TriggerType?)trigger.SetOrRemoveAnnotation(CosmosAnnotationNames.TriggerType, triggerType, fromDataAnnotation)?.Value;

/// <summary>
/// Gets the <see cref="ConfigurationSource" /> for the Cosmos DB trigger type.
/// </summary>
/// <param name="trigger">The trigger.</param>
/// <returns>The <see cref="ConfigurationSource" /> for the Cosmos DB trigger type.</returns>
public static ConfigurationSource? GetTriggerTypeConfigurationSource(this IConventionTrigger trigger)
=> trigger.FindAnnotation(CosmosAnnotationNames.TriggerType)?.GetConfigurationSource();

/// <summary>
/// Gets the Cosmos DB trigger operation for this trigger.
/// </summary>
/// <param name="trigger">The trigger.</param>
/// <returns>The Cosmos DB trigger operation.</returns>
public static TriggerOperation? GetTriggerOperation(this IReadOnlyTrigger trigger)
=> (TriggerOperation?)trigger[CosmosAnnotationNames.TriggerOperation];

/// <summary>
/// Sets the Cosmos DB trigger operation for this trigger.
/// </summary>
/// <param name="trigger">The trigger.</param>
/// <param name="triggerOperation">The Cosmos DB trigger operation.</param>
public static void SetTriggerOperation(this IMutableTrigger trigger, TriggerOperation? triggerOperation)
=> trigger.SetOrRemoveAnnotation(CosmosAnnotationNames.TriggerOperation, triggerOperation);

/// <summary>
/// Sets the Cosmos DB trigger operation for this trigger.
/// </summary>
/// <param name="trigger">The trigger.</param>
/// <param name="triggerOperation">The Cosmos DB trigger operation.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The configured value.</returns>
public static TriggerOperation? SetTriggerOperation(
this IConventionTrigger trigger,
TriggerOperation? triggerOperation,
bool fromDataAnnotation = false)
=> (TriggerOperation?)trigger.SetOrRemoveAnnotation(CosmosAnnotationNames.TriggerOperation, triggerOperation, fromDataAnnotation)?.Value;

/// <summary>
/// Gets the <see cref="ConfigurationSource" /> for the Cosmos DB trigger operation.
/// </summary>
/// <param name="trigger">The trigger.</param>
/// <returns>The <see cref="ConfigurationSource" /> for the Cosmos DB trigger operation.</returns>
public static ConfigurationSource? GetTriggerOperationConfigurationSource(this IConventionTrigger trigger)
=> trigger.FindAnnotation(CosmosAnnotationNames.TriggerOperation)?.GetConfigurationSource();
}
Original file line number Diff line number Diff line change
Expand Up @@ -633,4 +633,41 @@ protected override void ValidatePropertyMapping(
}
}
}

/// <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 override void ValidateTriggers(
IModel model,
IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
{
base.ValidateTriggers(model, logger);

foreach (var entityType in model.GetEntityTypes())
{
foreach (var trigger in entityType.GetDeclaredTriggers())
{
if (entityType.BaseType != null)
{
throw new InvalidOperationException(
CosmosStrings.TriggerOnDerivedType(trigger.ModelName, entityType.DisplayName(), entityType.BaseType.DisplayName()));
}

if (trigger.GetTriggerType() == null)
{
throw new InvalidOperationException(
CosmosStrings.TriggerMissingType(trigger.ModelName, entityType.DisplayName()));
}

if (trigger.GetTriggerOperation() == null)
{
throw new InvalidOperationException(
CosmosStrings.TriggerMissingOperation(trigger.ModelName, entityType.DisplayName()));
}
}
}
}
}
16 changes: 16 additions & 0 deletions src/EFCore.Cosmos/Metadata/Internal/CosmosAnnotationNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,20 @@ public static class CosmosAnnotationNames
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public const string ModelDependencies = Prefix + "ModelDependencies";

/// <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>
public const string TriggerType = Prefix + "TriggerType";

/// <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>
public const string TriggerOperation = Prefix + "TriggerOperation";
}
24 changes: 24 additions & 0 deletions src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/EFCore.Cosmos/Properties/CosmosStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,15 @@
<data name="TransactionsNotSupported" xml:space="preserve">
<value>The Cosmos database provider does not support transactions.</value>
</data>
<data name="TriggerMissingOperation" xml:space="preserve">
<value>Trigger '{trigger}' on entity type '{entityType}' does not have a trigger operation configured. Use 'HasTriggerOperation()' to configure the trigger operation.</value>
</data>
<data name="TriggerMissingType" xml:space="preserve">
<value>Trigger '{trigger}' on entity type '{entityType}' does not have a trigger type configured. Use 'HasTriggerType()' to configure the trigger type.</value>
</data>
<data name="TriggerOnDerivedType" xml:space="preserve">
<value>Trigger '{trigger}' is defined on entity type '{entityType}' which inherits from '{baseType}'. Triggers can only be defined on root entity types.</value>
</data>
<data name="UnableToBindMemberToEntityProjection" xml:space="preserve">
<value>Unable to bind '{memberType}' '{member}' to an entity projection of '{entityType}'.</value>
</data>
Expand Down
Loading
Loading