Skip to content

Commit

Permalink
Implement ExecuteUpdate
Browse files Browse the repository at this point in the history
Resolves #795
  • Loading branch information
smitpatel committed Aug 10, 2022
1 parent d6f1418 commit 8d7ac14
Show file tree
Hide file tree
Showing 50 changed files with 2,648 additions and 301 deletions.
68 changes: 64 additions & 4 deletions src/EFCore.Relational/Extensions/RelationalQueryableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ internal static readonly MethodInfo AsSplitQueryMethodInfo
#region ExecuteDelete

/// <summary>
/// Deletes all entity instances which match the LINQ query from the database.
/// Deletes all database rows for the entity instances which match the LINQ query from the database.
/// </summary>
/// <remarks>
/// <para>
Expand All @@ -251,12 +251,12 @@ internal static readonly MethodInfo AsSplitQueryMethodInfo
/// </para>
/// </remarks>
/// <param name="source">The source query.</param>
/// <returns>The total number of entity instances deleted from the database.</returns>
/// <returns>The total number of rows deleted in the database.</returns>
public static int ExecuteDelete<TSource>(this IQueryable<TSource> source)
=> source.Provider.Execute<int>(Expression.Call(ExecuteDeleteMethodInfo.MakeGenericMethod(typeof(TSource)), source.Expression));

/// <summary>
/// Asynchronously deletes all entity instances which match the LINQ query from the database.
/// Asynchronously deletes database rows for the entity instances which match the LINQ query from the database.
/// </summary>
/// <remarks>
/// <para>
Expand All @@ -272,7 +272,7 @@ public static int ExecuteDelete<TSource>(this IQueryable<TSource> source)
/// </remarks>
/// <param name="source">The source query.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
/// <returns>The total number of entity instances deleted from the database.</returns>
/// <returns>The total number of rows deleted in the database.</returns>
public static Task<int> ExecuteDeleteAsync<TSource>(this IQueryable<TSource> source, CancellationToken cancellationToken = default)
=> source.Provider is IAsyncQueryProvider provider
? provider.ExecuteAsync<Task<int>>(
Expand All @@ -283,4 +283,64 @@ internal static readonly MethodInfo ExecuteDeleteMethodInfo
= typeof(RelationalQueryableExtensions).GetTypeInfo().GetDeclaredMethod(nameof(ExecuteDelete))!;

#endregion

#region ExecuteUpdate

/// <summary>
/// Updates all database rows for the entity instances which match the LINQ query from the database.
/// </summary>
/// <remarks>
/// <para>
/// This operation executes immediately against the database, rather than being deferred until
/// <see cref="DbContext.SaveChanges()" /> is called. It also does not interact with the EF change tracker in any way:
/// entity instances which happen to be tracked when this operation is invoked aren't taken into account, and aren't updated
/// to reflect the changes.
/// </para>
/// <para>
/// See <see href="https://aka.ms/efcore-docs-bulk-operations">Executing bulk operations with EF Core</see>
/// for more information and examples.
/// </para>
/// </remarks>
/// <param name="source">The source query.</param>
/// <param name="setPropertyStatements">A collection of set property statements specifying properties to update.</param>
/// <returns>The total number of rows updated in the database.</returns>
public static int ExecuteUpdate<TSource>(
this IQueryable<TSource> source,
Expression<Func<SetPropertyStatements<TSource>, SetPropertyStatements<TSource>>> setPropertyStatements)
=> source.Provider.Execute<int>(
Expression.Call(ExecuteUpdateMethodInfo.MakeGenericMethod(typeof(TSource)), source.Expression, setPropertyStatements));

/// <summary>
/// Asynchronously updates database rows for the entity instances which match the LINQ query from the database.
/// </summary>
/// <remarks>
/// <para>
/// This operation executes immediately against the database, rather than being deferred until
/// <see cref="DbContext.SaveChanges()" /> is called. It also does not interact with the EF change tracker in any way:
/// entity instances which happen to be tracked when this operation is invoked aren't taken into account, and aren't updated
/// to reflect the changes.
/// </para>
/// <para>
/// See <see href="https://aka.ms/efcore-docs-bulk-operations">Executing bulk operations with EF Core</see>
/// for more information and examples.
/// </para>
/// </remarks>
/// <param name="source">The source query.</param>
/// <param name="setPropertyStatements">A collection of set property statements specifying properties to update.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
/// <returns>The total number of rows updated in the database.</returns>
public static Task<int> ExecuteUpdateAsync<TSource>(
this IQueryable<TSource> source,
Expression<Func<SetPropertyStatements<TSource>, SetPropertyStatements<TSource>>> setPropertyStatements,
CancellationToken cancellationToken = default)
=> source.Provider is IAsyncQueryProvider provider
? provider.ExecuteAsync<Task<int>>(
Expression.Call(
ExecuteUpdateMethodInfo.MakeGenericMethod(typeof(TSource)), source.Expression, setPropertyStatements), cancellationToken)
: throw new InvalidOperationException(CoreStrings.IQueryableProviderNotAsync);

internal static readonly MethodInfo ExecuteUpdateMethodInfo
= typeof(RelationalQueryableExtensions).GetTypeInfo().GetDeclaredMethod(nameof(ExecuteUpdate))!;

#endregion
}
Loading

0 comments on commit 8d7ac14

Please sign in to comment.