Skip to content

Commit

Permalink
ExecuteUpdate: Implement support for DEFAULT
Browse files Browse the repository at this point in the history
Resolves #28660
  • Loading branch information
smitpatel committed Aug 19, 2022
1 parent 23227c8 commit 518ff83
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,12 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
}
}

// EF.Default
if (methodCallExpression.Method.IsEFDefaultMethod())
{
return new SqlFragmentExpression("DEFAULT");
}

var method = methodCallExpression.Method;
var arguments = methodCallExpression.Arguments;
EnumerableExpression? enumerableExpression = null;
Expand Down
12 changes: 12 additions & 0 deletions src/EFCore/EF.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public static partial class EF
internal static readonly MethodInfo PropertyMethod
= typeof(EF).GetTypeInfo().GetDeclaredMethod(nameof(Property))!;

internal static readonly MethodInfo DefaultMethod
= typeof(EF).GetTypeInfo().GetDeclaredMethod(nameof(Default))!;

/// <summary>
/// This flag is set to <see langword="true" /> when code is being run from a design-time tool, such
/// as "dotnet ef" or one of the Package Manager Console PowerShell commands "Add-Migration", "Update-Database", etc.
Expand Down Expand Up @@ -55,6 +58,15 @@ public static TProperty Property<TProperty>(
[NotParameterized] string propertyName)
=> throw new InvalidOperationException(CoreStrings.PropertyMethodInvoked);

/// <summary>
/// .
/// </summary>
/// <typeparam name="T">.</typeparam>
/// <returns>.</returns>
public static T Default<T>()
// TODO: Update exception message
=> throw new InvalidOperationException(CoreStrings.PropertyMethodInvoked);

/// <summary>
/// Provides CLR methods that get translated to database functions when used in LINQ to Entities queries.
/// Calling these methods in other contexts (e.g. LINQ to Objects) will throw a <see cref="NotSupportedException" />.
Expand Down
27 changes: 20 additions & 7 deletions src/EFCore/Infrastructure/MethodInfoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,24 @@ public static class MethodInfoExtensions
/// </summary>
/// <param name="methodInfo">The method.</param>
/// <returns><see langword="true" /> if the method is <see cref="EF.Property{TProperty}" />; <see langword="false" /> otherwise.</returns>
public static bool IsEFPropertyMethod(this MethodInfo? methodInfo)
=> Equals(methodInfo, EF.PropertyMethod)
// fallback to string comparison because MethodInfo.Equals is not
// always true in .NET Native even if methods are the same
|| methodInfo?.IsGenericMethod == true
&& methodInfo.Name == nameof(EF.Property)
&& methodInfo.DeclaringType?.FullName == EFTypeName;
public static bool IsEFPropertyMethod(this MethodInfo methodInfo)
=> methodInfo.IsGenericMethod
&& (Equals(methodInfo.GetGenericMethodDefinition(), EF.PropertyMethod)
// fallback to string comparison because MethodInfo.Equals is not
// always true in .NET Native even if methods are the same
|| (methodInfo.Name == nameof(EF.Property)
&& methodInfo.DeclaringType?.FullName == EFTypeName));

/// <summary>
/// Returns <see langword="true" /> if the given method is <see cref="EF.Default{T}" />.
/// </summary>
/// <param name="methodInfo">The method.</param>
/// <returns><see langword="true" /> if the method is <see cref="EF.Default{T}" />; <see langword="false" /> otherwise.</returns>
public static bool IsEFDefaultMethod(this MethodInfo methodInfo)
=> methodInfo.IsGenericMethod
&& (Equals(methodInfo.GetGenericMethodDefinition(), EF.DefaultMethod)
// fallback to string comparison because MethodInfo.Equals is not
// always true in .NET Native even if methods are the same
|| (methodInfo.Name == nameof(EF.DefaultMethod)
&& methodInfo.DeclaringType?.FullName == EFTypeName));
}
3 changes: 2 additions & 1 deletion src/EFCore/Query/EvaluatableExpressionFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ public virtual bool IsEvaluatableExpression(Expression expression, IModel model)
|| Equals(method, RandomNextNoArgs)
|| Equals(method, RandomNextOneArg)
|| Equals(method, RandomNextTwoArgs)
|| method.DeclaringType == typeof(DbFunctionsExtensions))
|| method.DeclaringType == typeof(DbFunctionsExtensions)
|| method.IsEFDefaultMethod())
{
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,17 @@ public virtual Task Update_Where_set_constant(bool async)
rowsAffectedCount: 8,
(b, a) => Assert.All(a, c => Assert.Equal("Updated", c.ContactName)));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Update_Where_set_default(bool async)
=> AssertUpdate(
async,
ss => ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("F")),
e => e,
s => s.SetProperty(c => c.ContactName, c => EF.Default<string>()),
rowsAffectedCount: 8,
(b, a) => Assert.All(a, c => Assert.Null(c.ContactName)));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Update_Where_parameter_set_constant(bool async)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,17 @@ FROM [Customers] AS [c]
WHERE [c].[CustomerID] LIKE N'F%'");
}

public override async Task Update_Where_set_default(bool async)
{
await base.Update_Where_set_default(async);

AssertExecuteUpdateSql(
@"UPDATE [c]
SET [c].[ContactName] = DEFAULT
FROM [Customers] AS [c]
WHERE [c].[CustomerID] LIKE N'F%'");
}

public override async Task Update_Where_parameter_set_constant(bool async)
{
await base.Update_Where_parameter_set_constant(async);
Expand Down
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.Data.Sqlite;
using Microsoft.EntityFrameworkCore.Sqlite.Internal;

namespace Microsoft.EntityFrameworkCore.BulkUpdates;
Expand Down Expand Up @@ -549,6 +550,9 @@ public override async Task Update_Where_set_constant(bool async)
WHERE ""c"".""CustomerID"" LIKE 'F%'");
}

public override Task Update_Where_set_default(bool async)
=> Assert.ThrowsAsync<SqliteException>(() => base.Update_Where_set_default(async));

public override async Task Update_Where_parameter_set_constant(bool async)
{
await base.Update_Where_parameter_set_constant(async);
Expand Down

0 comments on commit 518ff83

Please sign in to comment.