Skip to content

Commit

Permalink
Add OwnedNavigationBuilder.HasIndex with name
Browse files Browse the repository at this point in the history
Add IConventionEntityTypeBuilder API for UseSqlReturningClause and UseSqlOutputClause

Fixes #33739
Fixes #33287
  • Loading branch information
AndriySvyryd committed Aug 14, 2024
1 parent 37599d2 commit 0cb3b24
Show file tree
Hide file tree
Showing 20 changed files with 543 additions and 52 deletions.
74 changes: 48 additions & 26 deletions src/EFCore.Cosmos/Storage/Internal/CosmosDatabaseCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,7 @@ public virtual bool EnsureCreated()
InsertData();
}

var coreOptionsExtension =
_contextOptions.FindExtension<CoreOptionsExtension>()
?? new CoreOptionsExtension();

var seed = coreOptionsExtension.Seeder;
if (seed != null)
{
seed(_currentContext.Context, created);
}
else if (coreOptionsExtension.AsyncSeeder != null)
{
throw new InvalidOperationException(CoreStrings.MissingSeeder);
}
SeedData(created);

return created;
}
Expand Down Expand Up @@ -104,19 +92,7 @@ public virtual async Task<bool> EnsureCreatedAsync(CancellationToken cancellatio
await InsertDataAsync(cancellationToken).ConfigureAwait(false);
}

var coreOptionsExtension =
_contextOptions.FindExtension<CoreOptionsExtension>()
?? new CoreOptionsExtension();

var seedAsync = coreOptionsExtension.AsyncSeeder;
if (seedAsync != null)
{
await seedAsync(_currentContext.Context, created, cancellationToken).ConfigureAwait(false);
}
else if (coreOptionsExtension.Seeder != null)
{
throw new InvalidOperationException(CoreStrings.MissingSeeder);
}
await SeedDataAsync(created, cancellationToken).ConfigureAwait(false);

return created;
}
Expand Down Expand Up @@ -223,6 +199,52 @@ private IUpdateAdapter AddModelData()
return updateAdapter;
}

/// <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 virtual void SeedData(bool created)
{
var coreOptionsExtension =
_contextOptions.FindExtension<CoreOptionsExtension>()
?? new CoreOptionsExtension();

var seed = coreOptionsExtension.Seeder;
if (seed != null)
{
seed(_currentContext.Context, created);
}
else if (coreOptionsExtension.AsyncSeeder != null)
{
throw new InvalidOperationException(CoreStrings.MissingSeeder);
}
}

/// <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 virtual async Task SeedDataAsync(bool created, CancellationToken cancellationToken = default)
{
var coreOptionsExtension =
_contextOptions.FindExtension<CoreOptionsExtension>()
?? new CoreOptionsExtension();

var seedAsync = coreOptionsExtension.AsyncSeeder;
if (seedAsync != null)
{
await seedAsync(_currentContext.Context, created, cancellationToken).ConfigureAwait(false);
}
else if (coreOptionsExtension.Seeder != null)
{
throw new InvalidOperationException(CoreStrings.MissingSeeder);
}
}

/// <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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,111 @@ public static bool CanSetIsMemoryOptimized(
bool fromDataAnnotation = false)
=> entityTypeBuilder.CanSetAnnotation(SqlServerAnnotationNames.MemoryOptimized, memoryOptimized, fromDataAnnotation);

/// <summary>
/// Sets a value indicating whether to use the SQL OUTPUT clause when saving changes to the table.
/// The OUTPUT clause is incompatible with certain SQL Server features, such as tables with triggers.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="entityTypeBuilder">The builder for the entity type being configured.</param>
/// <param name="useSqlOutputClause">The value to set.</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 IConventionEntityTypeBuilder? UseSqlOutputClause(
this IConventionEntityTypeBuilder entityTypeBuilder,
bool? useSqlOutputClause,
bool fromDataAnnotation = false)
{
if (!entityTypeBuilder.CanUseSqlOutputClause(useSqlOutputClause, fromDataAnnotation))
{
return null;
}

entityTypeBuilder.Metadata.UseSqlOutputClause(useSqlOutputClause, fromDataAnnotation);
return entityTypeBuilder;
}

/// <summary>
/// Sets a value indicating whether to use the SQL OUTPUT clause when saving changes to the table.
/// The OUTPUT clause is incompatible with certain SQL Server features, such as tables with triggers.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="entityTypeBuilder">The builder for the entity type being configured.</param>
/// <param name="useSqlOutputClause">The value to set.</param>
/// <param name="storeObject">The identifier of the table-like store object.</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 IConventionEntityTypeBuilder? UseSqlOutputClause(
this IConventionEntityTypeBuilder entityTypeBuilder,
bool? useSqlOutputClause,
in StoreObjectIdentifier storeObject,
bool fromDataAnnotation = false)
{
if (!entityTypeBuilder.CanUseSqlOutputClause(useSqlOutputClause, storeObject, fromDataAnnotation))
{
return null;
}

entityTypeBuilder.Metadata.UseSqlOutputClause(useSqlOutputClause, storeObject, fromDataAnnotation);
return entityTypeBuilder;
}

/// <summary>
/// Returns a value indicating whether this entity type can be configured to use the SQL OUTPUT clause
/// using the specified configuration source.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="entityTypeBuilder">The builder for the entity type being configured.</param>
/// <param name="useSqlOutputClause">The value to set.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns><see langword="true" /> if the configuration can be applied.</returns>
public static bool CanUseSqlOutputClause(
this IConventionEntityTypeBuilder entityTypeBuilder,
bool? useSqlOutputClause,
bool fromDataAnnotation = false)
=> entityTypeBuilder.CanSetAnnotation(
SqlServerAnnotationNames.UseSqlOutputClause,
useSqlOutputClause,
fromDataAnnotation);

/// <summary>
/// Returns a value indicating whether this entity type can be configured to use the SQL OUTPUT clause
/// using the specified configuration source.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="entityTypeBuilder">The builder for the entity type being configured.</param>
/// <param name="useSqlOutputClause">The value to set.</param>
/// <param name="storeObject">The identifier of the table-like store object.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns><see langword="true" /> if the configuration can be applied.</returns>
public static bool CanUseSqlOutputClause(
this IConventionEntityTypeBuilder entityTypeBuilder,
bool? useSqlOutputClause,
in StoreObjectIdentifier storeObject,
bool fromDataAnnotation = false)
=> StoreObjectIdentifier.Create(entityTypeBuilder.Metadata, storeObject.StoreObjectType) == storeObject
? entityTypeBuilder.CanSetAnnotation(
SqlServerAnnotationNames.UseSqlOutputClause,
useSqlOutputClause,
fromDataAnnotation)
: entityTypeBuilder.Metadata.GetOrCreateMappingFragment(storeObject, fromDataAnnotation).Builder.CanSetAnnotation(
SqlServerAnnotationNames.UseSqlOutputClause,
useSqlOutputClause,
fromDataAnnotation);

/// <summary>
/// Configures the table as temporal.
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions src/EFCore.SqlServer/Extensions/SqlServerEntityTypeExtensions.cs
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.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.SqlServer.Metadata.Internal;

// ReSharper disable once CheckNamespace
Expand Down Expand Up @@ -344,6 +345,18 @@ public static void UseSqlOutputClause(this IMutableEntityType entityType, bool?
public static ConfigurationSource? GetUseSqlOutputClauseConfigurationSource(this IConventionEntityType entityType)
=> entityType.FindAnnotation(SqlServerAnnotationNames.UseSqlOutputClause)?.GetConfigurationSource();

/// <summary>
/// Gets the configuration source for whether to use the SQL OUTPUT clause when saving changes to the table.
/// </summary>
/// <param name="entityType">The entity type.</param>
/// <param name="storeObject">The identifier of the table-like store object.</param>
/// <returns>The configuration source for the memory-optimized setting.</returns>
public static ConfigurationSource? GetUseSqlOutputClauseConfigurationSource(
this IConventionEntityType entityType, in StoreObjectIdentifier storeObject)
=> StoreObjectIdentifier.Create(entityType, storeObject.StoreObjectType) == storeObject
? entityType.GetUseSqlOutputClauseConfigurationSource()
: (entityType.FindMappingFragment(storeObject)?.GetUseSqlOutputClauseConfigurationSource());

/// <summary>
/// Returns a value indicating whether to use the SQL OUTPUT clause when saving changes to the specified table.
/// The OUTPUT clause is incompatible with certain SQL Server features, such as tables with triggers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static bool IsSqlOutputClauseUsed(this IReadOnlyEntityTypeMappingFragment
/// <param name="fragment">The entity type mapping fragment.</param>
/// <param name="useSqlOutputClause">The value to set.</param>
public static void UseSqlOutputClause(this IMutableEntityTypeMappingFragment fragment, bool? useSqlOutputClause)
=> fragment.SetAnnotation(SqlServerAnnotationNames.UseSqlOutputClause, useSqlOutputClause);
=> fragment.SetOrRemoveAnnotation(SqlServerAnnotationNames.UseSqlOutputClause, useSqlOutputClause);

/// <summary>
/// Sets whether to use the SQL OUTPUT clause when saving changes to the associated table.
Expand All @@ -41,7 +41,7 @@ public static void UseSqlOutputClause(this IMutableEntityTypeMappingFragment fra
this IConventionEntityTypeMappingFragment fragment,
bool? useSqlOutputClause,
bool fromDataAnnotation = false)
=> (bool?)fragment.SetAnnotation(SqlServerAnnotationNames.UseSqlOutputClause, useSqlOutputClause, fromDataAnnotation)?.Value;
=> (bool?)fragment.SetOrRemoveAnnotation(SqlServerAnnotationNames.UseSqlOutputClause, useSqlOutputClause, fromDataAnnotation)?.Value;

/// <summary>
/// Gets the configuration source for the setting whether to use the SQL OUTPUT clause when saving changes to the associated table.
Expand Down
123 changes: 123 additions & 0 deletions src/EFCore.Sqlite.Core/Extensions/SqliteEntityTypeBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// 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.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Sqlite.Metadata.Internal;

// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore;

/// <summary>
/// Entity type builder extension methods for Sqlite-specific metadata.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see>, and
/// <see href="https://aka.ms/efcore-docs-sqlite">Accessing Sqlite databases with EF Core</see> for more information and examples.
/// </remarks>
public static class SqliteEntityTypeBuilderExtensions
{
/// <summary>
/// Sets a value indicating whether to use the SQL RETURNING clause when saving changes to the table.
/// The RETURNING clause is incompatible with certain Sqlite features, such as virtual tables or tables with AFTER triggers.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="entityTypeBuilder">The builder for the entity type being configured.</param>
/// <param name="useSqlReturningClause">The value to set.</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 IConventionEntityTypeBuilder? UseSqlReturningClause(
this IConventionEntityTypeBuilder entityTypeBuilder,
bool? useSqlReturningClause,
bool fromDataAnnotation = false)
{
if (!entityTypeBuilder.CanUseSqlReturningClause(useSqlReturningClause, fromDataAnnotation))
{
return null;
}

entityTypeBuilder.Metadata.UseSqlReturningClause(useSqlReturningClause, fromDataAnnotation);
return entityTypeBuilder;
}

/// <summary>
/// Sets a value indicating whether to use the SQL RETURNING clause when saving changes to the table.
/// The RETURNING clause is incompatible with certain Sqlite features, such as virtual tables or tables with AFTER triggers.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="entityTypeBuilder">The builder for the entity type being configured.</param>
/// <param name="useSqlReturningClause">The value to set.</param>
/// <param name="storeObject">The identifier of the table-like store object.</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 IConventionEntityTypeBuilder? UseSqlReturningClause(
this IConventionEntityTypeBuilder entityTypeBuilder,
bool? useSqlReturningClause,
in StoreObjectIdentifier storeObject,
bool fromDataAnnotation = false)
{
if (!entityTypeBuilder.CanUseSqlReturningClause(useSqlReturningClause, storeObject, fromDataAnnotation))
{
return null;
}

entityTypeBuilder.Metadata.UseSqlReturningClause(useSqlReturningClause, storeObject, fromDataAnnotation);
return entityTypeBuilder;
}

/// <summary>
/// Returns a value indicating whether this entity type can be configured to use the SQL RETURNING clause
/// using the specified configuration source.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="entityTypeBuilder">The builder for the entity type being configured.</param>
/// <param name="useSqlReturningClause">The value to set.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns><see langword="true" /> if the configuration can be applied.</returns>
public static bool CanUseSqlReturningClause(
this IConventionEntityTypeBuilder entityTypeBuilder,
bool? useSqlReturningClause,
bool fromDataAnnotation = false)
=> entityTypeBuilder.CanSetAnnotation(
SqliteAnnotationNames.UseSqlReturningClause,
useSqlReturningClause,
fromDataAnnotation);

/// <summary>
/// Returns a value indicating whether this entity type can be configured to use the SQL RETURNING clause
/// using the specified configuration source.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="entityTypeBuilder">The builder for the entity type being configured.</param>
/// <param name="useSqlReturningClause">The value to set.</param>
/// <param name="storeObject">The identifier of the table-like store object.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns><see langword="true" /> if the configuration can be applied.</returns>
public static bool CanUseSqlReturningClause(
this IConventionEntityTypeBuilder entityTypeBuilder,
bool? useSqlReturningClause,
in StoreObjectIdentifier storeObject,
bool fromDataAnnotation = false)
=> StoreObjectIdentifier.Create(entityTypeBuilder.Metadata, storeObject.StoreObjectType) == storeObject
? entityTypeBuilder.CanSetAnnotation(
SqliteAnnotationNames.UseSqlReturningClause,
useSqlReturningClause,
fromDataAnnotation)
: entityTypeBuilder.Metadata.GetOrCreateMappingFragment(storeObject, fromDataAnnotation).Builder.CanSetAnnotation(
SqliteAnnotationNames.UseSqlReturningClause,
useSqlReturningClause,
fromDataAnnotation);
}
Loading

0 comments on commit 0cb3b24

Please sign in to comment.