Skip to content

Commit

Permalink
Merge branch 'release/7.0-rc1' into release/7.0
Browse files Browse the repository at this point in the history
  • Loading branch information
smitpatel committed Aug 22, 2022
2 parents 0efc506 + 022df8f commit 2108143
Show file tree
Hide file tree
Showing 34 changed files with 395 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ protected override void ProcessModelAnnotations(
/// <param name="runtimeEntityType">The target entity type that will contain the annotations.</param>
/// <param name="runtime">Indicates whether the given annotations are runtime annotations.</param>
protected override void ProcessEntityTypeAnnotations(
IDictionary<string, object?> annotations,
Dictionary<string, object?> annotations,
IEntityType entityType,
RuntimeEntityType runtimeEntityType,
bool runtime)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,13 +342,13 @@ internal static readonly MethodInfo ExecuteDeleteMethodInfo
/// </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="setPropertyCalls">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)
Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> setPropertyCalls)
=> source.Provider.Execute<int>(
Expression.Call(ExecuteUpdateMethodInfo.MakeGenericMethod(typeof(TSource)), source.Expression, setPropertyStatements));
Expression.Call(ExecuteUpdateMethodInfo.MakeGenericMethod(typeof(TSource)), source.Expression, setPropertyCalls));

/// <summary>
/// Asynchronously updates database rows for the entity instances which match the LINQ query from the database.
Expand All @@ -366,17 +366,17 @@ public static int ExecuteUpdate<TSource>(
/// </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="setPropertyCalls">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,
Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> setPropertyCalls,
CancellationToken cancellationToken = default)
=> source.Provider is IAsyncQueryProvider provider
? provider.ExecuteAsync<Task<int>>(
Expression.Call(
ExecuteUpdateMethodInfo.MakeGenericMethod(typeof(TSource)), source.Expression, setPropertyStatements), cancellationToken)
ExecuteUpdateMethodInfo.MakeGenericMethod(typeof(TSource)), source.Expression, setPropertyCalls), cancellationToken)
: throw new InvalidOperationException(CoreStrings.IQueryableProviderNotAsync);

internal static readonly MethodInfo ExecuteUpdateMethodInfo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ protected override void ProcessModelAnnotations(
/// <param name="runtimeEntityType">The target entity type that will contain the annotations.</param>
/// <param name="runtime">Indicates whether the given annotations are runtime annotations.</param>
protected override void ProcessEntityTypeAnnotations(
IDictionary<string, object?> annotations,
Dictionary<string, object?> annotations,
IEntityType entityType,
RuntimeEntityType runtimeEntityType,
bool runtime)
Expand Down Expand Up @@ -405,7 +405,7 @@ protected virtual void ProcessPropertyOverridesAnnotations(
/// <param name="runtimeKey">The target key that will contain the annotations.</param>
/// <param name="runtime">Indicates whether the given annotations are runtime annotations.</param>
protected override void ProcessKeyAnnotations(
IDictionary<string, object?> annotations,
Dictionary<string, object?> annotations,
IKey key,
RuntimeKey runtimeKey,
bool runtime)
Expand Down

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

2 changes: 1 addition & 1 deletion src/EFCore.Relational/Properties/RelationalStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@
<value>Unable to translate a collection subquery in a projection since either parent or the subquery doesn't project necessary information required to uniquely identify it and correctly generate results on the client side. This can happen when trying to correlate on keyless entity type. This can also happen for some cases of projection before 'Distinct' or some shapes of grouping key in case of 'GroupBy'. These should either contain all key properties of the entity that the operation is applied on, or only contain simple property access expressions.</value>
</data>
<data name="InvalidArgumentToExecuteUpdate" xml:space="preserve">
<value>The 'setPropertyStatements' argument to 'ExecuteUpdate' may only contain a chain of 'SetProperty' expressing the properties to be updated.</value>
<value>The 'setPropertyCalls' argument to 'ExecuteUpdate' may only contain a chain of 'SetProperty' expressing the properties to be updated.</value>
</data>
<data name="InvalidCommandTimeout" xml:space="preserve">
<value>The specified 'CommandTimeout' value '{value}' is not valid. It must be a positive number.</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class SelectExpressionPruningExpressionVisitor : ExpressionVisitor
case UpdateExpression updateExpression:
return updateExpression.Update(
updateExpression.SelectExpression.Prune(),
updateExpression.SetColumnValues.Select(e => new SetColumnValue(e.Column, (SqlExpression)Visit(e.Value))).ToList());
updateExpression.ColumnValueSetters.Select(e => new ColumnValueSetter(e.Column, (SqlExpression)Visit(e.Value))).ToList());

default:
return base.Visit(expression);
Expand Down
33 changes: 16 additions & 17 deletions src/EFCore.Relational/Query/JsonQueryExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public JsonQueryExpression(
collection,
keyPropertyMap,
type,
jsonPath: new SqlConstantExpression(Constant("$"), typeMapping: null),
path: new SqlConstantExpression(Constant("$"), typeMapping: null),
jsonColumn.IsNullable)
{
}
Expand All @@ -44,7 +44,7 @@ private JsonQueryExpression(
bool collection,
IReadOnlyDictionary<IProperty, ColumnExpression> keyPropertyMap,
Type type,
SqlExpression jsonPath,
SqlExpression path,
bool nullable)
{
Check.DebugAssert(entityType.FindPrimaryKey() != null, "primary key is null.");
Expand All @@ -54,7 +54,7 @@ private JsonQueryExpression(
IsCollection = collection;
_keyPropertyMap = keyPropertyMap;
Type = type;
JsonPath = jsonPath;
Path = path;
_nullable = nullable;
}

Expand All @@ -76,7 +76,7 @@ private JsonQueryExpression(
/// <summary>
/// The JSON path leading to the entity from the root of the JSON stored in the column.
/// </summary>
public virtual SqlExpression JsonPath { get; }
public virtual SqlExpression Path { get; }

/// <summary>
/// The value indicating whether this expression is nullable.
Expand Down Expand Up @@ -112,7 +112,7 @@ public virtual SqlExpression BindProperty(IProperty property)

var newPath = new SqlBinaryExpression(
ExpressionType.Add,
JsonPath,
Path,
pathSegment,
typeof(string),
typeMapping: null);
Expand Down Expand Up @@ -148,7 +148,7 @@ public virtual JsonQueryExpression BindNavigation(INavigation navigation)

var newJsonPath = new SqlBinaryExpression(
ExpressionType.Add,
JsonPath,
Path,
pathSegment,
typeof(string),
typeMapping: null);
Expand Down Expand Up @@ -190,27 +190,26 @@ public virtual JsonQueryExpression MakeNullable()
/// Makes this JSON query expression nullable re-using existing nullable key properties
/// </summary>
/// <returns>A new expression which has <see cref="IsNullable" /> property set to true.</returns>
[EntityFrameworkInternal]
public virtual JsonQueryExpression MakeNullable(IReadOnlyDictionary<IProperty, ColumnExpression> nullableKeyPropertyMap)
internal virtual JsonQueryExpression MakeNullable(IReadOnlyDictionary<IProperty, ColumnExpression> nullableKeyPropertyMap)
=> Update(
JsonColumn.MakeNullable(),
nullableKeyPropertyMap,
JsonPath,
Path,
nullable: true);

/// <inheritdoc />
public virtual void Print(ExpressionPrinter expressionPrinter)
{
expressionPrinter.Append("JsonQueryExpression(");
expressionPrinter.Visit(JsonColumn);
expressionPrinter.Append($", \"{string.Join(".", JsonPath)}\")");
expressionPrinter.Append($", \"{string.Join(".", Path)}\")");
}

/// <inheritdoc />
protected override Expression VisitChildren(ExpressionVisitor visitor)
{
var jsonColumn = (ColumnExpression)visitor.Visit(JsonColumn);
var jsonPath = (SqlExpression)visitor.Visit(JsonPath);
var jsonPath = (SqlExpression)visitor.Visit(Path);

// TODO: also visit columns in the _keyPropertyMap?
return Update(jsonColumn, _keyPropertyMap, jsonPath, IsNullable);
Expand All @@ -222,19 +221,19 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
/// </summary>
/// <param name="jsonColumn">The <see cref="JsonColumn" /> property of the result.</param>
/// <param name="keyPropertyMap">The map of key properties and columns they map to.</param>
/// <param name="jsonPath">The <see cref="JsonPath" /> property of the result.</param>
/// <param name="path">The <see cref="Path" /> property of the result.</param>
/// <param name="nullable">The <see cref="IsNullable" /> property of the result.</param>
/// <returns>This expression if no children changed, or an expression with the updated children.</returns>
public virtual JsonQueryExpression Update(
ColumnExpression jsonColumn,
IReadOnlyDictionary<IProperty, ColumnExpression> keyPropertyMap,
SqlExpression jsonPath,
SqlExpression path,
bool nullable)
=> jsonColumn != JsonColumn
|| keyPropertyMap.Count != _keyPropertyMap.Count
|| keyPropertyMap.Zip(_keyPropertyMap, (n, o) => n.Value != o.Value).Any(x => x)
|| jsonPath != JsonPath
? new JsonQueryExpression(EntityType, jsonColumn, IsCollection, keyPropertyMap, Type, jsonPath, nullable)
|| path != Path
? new JsonQueryExpression(EntityType, jsonColumn, IsCollection, keyPropertyMap, Type, path, nullable)
: this;

/// <inheritdoc />
Expand All @@ -248,7 +247,7 @@ private bool Equals(JsonQueryExpression jsonQueryExpression)
=> EntityType.Equals(jsonQueryExpression.EntityType)
&& JsonColumn.Equals(jsonQueryExpression.JsonColumn)
&& IsCollection.Equals(jsonQueryExpression.IsCollection)
&& JsonPath.Equals(jsonQueryExpression.JsonPath)
&& Path.Equals(jsonQueryExpression.Path)
&& IsNullable == jsonQueryExpression.IsNullable
&& KeyPropertyMapEquals(jsonQueryExpression._keyPropertyMap);

Expand All @@ -273,6 +272,6 @@ private bool KeyPropertyMapEquals(IReadOnlyDictionary<IProperty, ColumnExpressio
/// <inheritdoc />
public override int GetHashCode()
// not incorporating _keyPropertyMap into the hash, too much work
=> HashCode.Combine(EntityType, JsonColumn, IsCollection, JsonPath, IsNullable);
=> HashCode.Combine(EntityType, JsonColumn, IsCollection, Path, IsNullable);
}
}
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Query/QuerySqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1274,7 +1274,7 @@ protected override Expression VisitUpdate(UpdateExpression updateExpression)
using (_relationalCommandBuilder.Indent())
{
_relationalCommandBuilder.Append("SET ");
GenerateList(updateExpression.SetColumnValues,
GenerateList(updateExpression.ColumnValueSetters,
e =>
{
_relationalCommandBuilder.Append($"{_sqlGenerationHelper.DelimitIdentifier(e.Column.Name)} = ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1096,18 +1096,18 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
}

/// <summary>
/// Translates <see cref="RelationalQueryableExtensions.ExecuteUpdate{TSource}(IQueryable{TSource}, Expression{Func{SetPropertyStatements{TSource}, SetPropertyStatements{TSource}}})" /> method
/// Translates <see cref="RelationalQueryableExtensions.ExecuteUpdate{TSource}(IQueryable{TSource}, Expression{Func{SetPropertyCalls{TSource}, SetPropertyCalls{TSource}}})" /> method
/// over the given source.
/// </summary>
/// <param name="source">The shaped query on which the operator is applied.</param>
/// <param name="setPropertyStatements">The lambda expression containing <see cref="SetPropertyStatements{TSource}.SetProperty{TProperty}(Expression{Func{TSource, TProperty}}, Expression{Func{TSource, TProperty}})"/> statements.</param>
/// <param name="setPropertyCalls">The lambda expression containing <see cref="SetPropertyCalls{TSource}.SetProperty{TProperty}(Expression{Func{TSource, TProperty}}, Expression{Func{TSource, TProperty}})"/> statements.</param>
/// <returns>The non query after translation.</returns>
protected virtual NonQueryExpression? TranslateExecuteUpdate(
ShapedQueryExpression source,
LambdaExpression setPropertyStatements)
LambdaExpression setPropertyCalls)
{
var propertyValueLambdaExpressions = new List<(LambdaExpression, LambdaExpression)>();
PopulateSetPropertyStatements(setPropertyStatements.Body, propertyValueLambdaExpressions, setPropertyStatements.Parameters[0]);
PopulateSetPropertyCalls(setPropertyCalls.Body, propertyValueLambdaExpressions, setPropertyCalls.Parameters[0]);
if (TranslationErrorDetails != null)
{
return null;
Expand Down Expand Up @@ -1240,7 +1240,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
List<(LambdaExpression, LambdaExpression)> propertyValueLambdaExpressions,
List<Expression>? leftExpressions)
{
var setColumnValues = new List<SetColumnValue>();
var columnValueSetters = new List<ColumnValueSetter>();
for (var i = 0; i < propertyValueLambdaExpressions.Count; i++)
{
var (propertyExpression, valueExpression) = propertyValueLambdaExpressions[i];
Expand All @@ -1266,7 +1266,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
var translation = visitor._sqlTranslator.Translate(setter);
if (translation is SqlBinaryExpression { OperatorType: ExpressionType.Equal, Left: ColumnExpression column } sqlBinaryExpression)
{
setColumnValues.Add(new SetColumnValue(column, sqlBinaryExpression.Right));
columnValueSetters.Add(new ColumnValueSetter(column, sqlBinaryExpression.Right));
}
else
{
Expand All @@ -1280,10 +1280,10 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
selectExpression.ReplaceProjection(new List<Expression>());
selectExpression.ApplyProjection();

return new NonQueryExpression(new UpdateExpression(tableExpression, selectExpression, setColumnValues));
return new NonQueryExpression(new UpdateExpression(tableExpression, selectExpression, columnValueSetters));
}

void PopulateSetPropertyStatements(
void PopulateSetPropertyCalls(
Expression expression, List<(LambdaExpression, LambdaExpression)> list, ParameterExpression parameter)
{
switch (expression)
Expand All @@ -1294,13 +1294,13 @@ void PopulateSetPropertyStatements(

case MethodCallExpression methodCallExpression
when methodCallExpression.Method.IsGenericMethod
&& methodCallExpression.Method.Name == nameof(SetPropertyStatements<int>.SetProperty)
&& methodCallExpression.Method.Name == nameof(SetPropertyCalls<int>.SetProperty)
&& methodCallExpression.Method.DeclaringType!.IsGenericType
&& methodCallExpression.Method.DeclaringType.GetGenericTypeDefinition() == typeof(SetPropertyStatements<>):
&& methodCallExpression.Method.DeclaringType.GetGenericTypeDefinition() == typeof(SetPropertyCalls<>):

list.Add((methodCallExpression.Arguments[0].UnwrapLambdaFromQuote(),
methodCallExpression.Arguments[1].UnwrapLambdaFromQuote()));
PopulateSetPropertyStatements(methodCallExpression.Object!, list, parameter);
PopulateSetPropertyCalls(methodCallExpression.Object!, list, parameter);

break;

Expand Down
Loading

0 comments on commit 2108143

Please sign in to comment.