From d7512f92f031de6083d57e9360ddec89445dcb9e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Apr 2026 04:26:27 +0000 Subject: [PATCH 1/3] Rename BulkExecutionEnabled, LatestMigrationId, CompiledProviderName, JsonPath, JsonPathSegment, and Ordinals per API review Agent-Logs-Url: https://github.com/dotnet/efcore/sessions/56ecc586-e9c8-4c70-8a17-fbcaaed4a258 Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- src/EFCore.Cosmos/EFCore.Cosmos.baseline.json | 2 +- .../CosmosDbContextOptionsBuilder.cs | 4 +- .../Internal/CosmosDbOptionExtension.cs | 2 +- .../Design/CSharpMigrationsGenerator.cs | 2 +- .../EFCore.Relational.baseline.json | 28 ++--- .../Infrastructure/ModelSnapshot.cs | 2 +- .../{JsonPath.cs => StructuredJsonPath.cs} | 39 +++--- .../Metadata/IRelationalJsonElement.cs | 2 +- .../Internal/RelationalJsonElement.cs | 4 +- .../Metadata/Internal/RelationalJsonObject.cs | 6 +- .../StructuredJsonPathSegment.cs} | 14 +-- .../Update/ColumnModification.cs | 2 +- .../Update/ColumnModificationParameters.cs | 4 +- .../Update/IColumnModification.cs | 2 +- .../Update/ModificationCommand.cs | 2 +- .../Diagnostics/CoreLoggerExtensions.cs | 2 +- .../Diagnostics/ProviderMismatchEventData.cs | 8 +- src/EFCore/EFCore.baseline.json | 4 +- src/EFCore/Properties/CoreStrings.Designer.cs | 8 +- src/EFCore/Properties/CoreStrings.resx | 4 +- .../Update/CosmosBulkConcurrencyTest.cs | 2 +- .../Update/CosmosBulkEndToEndTest.cs | 2 +- .../CosmosBulkEndToEndTestNoBatching.cs | 2 +- .../Update/CosmosBulkExecutionTest.cs | 8 +- .../Update/CosmosBulkWarningTest.cs | 2 +- .../CosmosDbContextOptionsExtensionsTests.cs | 2 +- .../Design/OperationExecutorTest.cs | 2 +- ...rpMigrationsGeneratorTest.ModelSnapshot.cs | 8 +- .../Migrations/AnonymousArraySeedContext.cs | 2 +- .../Migrations/TypedArraySeedContext.cs | 2 +- .../Infrastructure/JsonPathTest.cs | 112 ----------------- .../Infrastructure/StructuredJsonPathTest.cs | 114 ++++++++++++++++++ 32 files changed, 201 insertions(+), 198 deletions(-) rename src/EFCore.Relational/Infrastructure/{JsonPath.cs => StructuredJsonPath.cs} (60%) rename src/EFCore.Relational/{Infrastructure/JsonPathSegment.cs => Metadata/StructuredJsonPathSegment.cs} (73%) delete mode 100644 test/EFCore.Tests/Infrastructure/JsonPathTest.cs create mode 100644 test/EFCore.Tests/Infrastructure/StructuredJsonPathTest.cs diff --git a/src/EFCore.Cosmos/EFCore.Cosmos.baseline.json b/src/EFCore.Cosmos/EFCore.Cosmos.baseline.json index 587881e0f81..fd6d654959a 100644 --- a/src/EFCore.Cosmos/EFCore.Cosmos.baseline.json +++ b/src/EFCore.Cosmos/EFCore.Cosmos.baseline.json @@ -135,7 +135,7 @@ "Member": "CosmosDbContextOptionsBuilder(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder optionsBuilder);" }, { - "Member": "virtual Microsoft.EntityFrameworkCore.Infrastructure.CosmosDbContextOptionsBuilder BulkExecutionEnabled(bool enabled = true);" + "Member": "virtual Microsoft.EntityFrameworkCore.Infrastructure.CosmosDbContextOptionsBuilder BulkExecutionAllowed(bool enabled = true);" }, { "Member": "virtual Microsoft.EntityFrameworkCore.Infrastructure.CosmosDbContextOptionsBuilder ConnectionMode(Microsoft.Azure.Cosmos.ConnectionMode connectionMode);" diff --git a/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs b/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs index cc1a2abcdf0..ce1a58f35ca 100644 --- a/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs +++ b/src/EFCore.Cosmos/Infrastructure/CosmosDbContextOptionsBuilder.cs @@ -243,8 +243,8 @@ public virtual CosmosDbContextOptionsBuilder SessionTokenManagementMode(SessionT /// Accessing Azure Cosmos DB with EF Core for more information and examples. /// /// to enable the Cosmos DB SDK bulk feature. - public virtual CosmosDbContextOptionsBuilder BulkExecutionEnabled(bool enabled = true) - => WithOption(e => e.BulkExecutionEnabled(enabled)); + public virtual CosmosDbContextOptionsBuilder BulkExecutionAllowed(bool enabled = true) + => WithOption(e => e.BulkExecutionAllowed(enabled)); /// /// Sets an option by cloning the extension used to store the settings. This ensures the builder diff --git a/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs b/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs index 2f0474bea3f..867600b6746 100644 --- a/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs +++ b/src/EFCore.Cosmos/Infrastructure/Internal/CosmosDbOptionExtension.cs @@ -607,7 +607,7 @@ public virtual CosmosOptionsExtension WithSessionTokenManagementMode(SessionToke /// 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. /// - public virtual CosmosOptionsExtension BulkExecutionEnabled(bool enabled) + public virtual CosmosOptionsExtension BulkExecutionAllowed(bool enabled) { var clone = Clone(); diff --git a/src/EFCore.Design/Migrations/Design/CSharpMigrationsGenerator.cs b/src/EFCore.Design/Migrations/Design/CSharpMigrationsGenerator.cs index b31350895c0..b6f3f1503e0 100644 --- a/src/EFCore.Design/Migrations/Design/CSharpMigrationsGenerator.cs +++ b/src/EFCore.Design/Migrations/Design/CSharpMigrationsGenerator.cs @@ -296,7 +296,7 @@ public override string GenerateSnapshot( .AppendLine("// If you encounter a merge conflict in the line below, it means you need to") .AppendLine("// discard one of the migration branches and recreate its migrations on top of") .AppendLine("// the other branch. See https://aka.ms/efcore-docs-migrations-conflicts for more info.") - .Append("public override string LatestMigrationId => ").Append(Code.Literal(latestMigrationId)).AppendLine(";") + .Append("public override string LastMigrationId => ").Append(Code.Literal(latestMigrationId)).AppendLine(";") .AppendLine(); } diff --git a/src/EFCore.Relational/EFCore.Relational.baseline.json b/src/EFCore.Relational/EFCore.Relational.baseline.json index 0fbf32cb4c4..f21ff100716 100644 --- a/src/EFCore.Relational/EFCore.Relational.baseline.json +++ b/src/EFCore.Relational/EFCore.Relational.baseline.json @@ -944,7 +944,7 @@ "Member": "virtual bool IsWrite { get; set; }" }, { - "Member": "virtual Microsoft.EntityFrameworkCore.Infrastructure.JsonPath? JsonPath { get; }" + "Member": "virtual Microsoft.EntityFrameworkCore.Infrastructure.StructuredJsonPath? JsonPath { get; }" }, { "Member": "virtual string? OriginalParameterName { get; }" @@ -994,7 +994,7 @@ "Member": "ColumnModificationParameters(Microsoft.EntityFrameworkCore.Update.IUpdateEntry? entry, Microsoft.EntityFrameworkCore.Metadata.IProperty? property, Microsoft.EntityFrameworkCore.Metadata.IColumnBase column, System.Func generateParameterName, Microsoft.EntityFrameworkCore.Storage.RelationalTypeMapping typeMapping, bool valueIsRead, bool valueIsWrite, bool columnIsKey, bool columnIsCondition, bool sensitiveLoggingEnabled);" }, { - "Member": "ColumnModificationParameters(string columnName, object? value, Microsoft.EntityFrameworkCore.Metadata.IProperty? property, string? columnType, Microsoft.EntityFrameworkCore.Storage.RelationalTypeMapping? typeMapping, Microsoft.EntityFrameworkCore.Infrastructure.JsonPath jsonPath, bool read, bool write, bool key, bool condition, bool sensitiveLoggingEnabled, bool? isNullable = null);" + "Member": "ColumnModificationParameters(string columnName, object? value, Microsoft.EntityFrameworkCore.Metadata.IProperty? property, string? columnType, Microsoft.EntityFrameworkCore.Storage.RelationalTypeMapping? typeMapping, Microsoft.EntityFrameworkCore.Infrastructure.StructuredJsonPath jsonPath, bool read, bool write, bool key, bool condition, bool sensitiveLoggingEnabled, bool? isNullable = null);" }, { "Member": "ColumnModificationParameters();" @@ -1050,7 +1050,7 @@ "Member": "bool IsWrite { get; init; }" }, { - "Member": "Microsoft.EntityFrameworkCore.Infrastructure.JsonPath? JsonPath { get; init; }" + "Member": "Microsoft.EntityFrameworkCore.Infrastructure.StructuredJsonPath? JsonPath { get; init; }" }, { "Member": "object? OriginalValue { get; init; }" @@ -3594,7 +3594,7 @@ "Member": "bool IsWrite { get; set; }" }, { - "Member": "Microsoft.EntityFrameworkCore.Infrastructure.JsonPath? JsonPath { get; }" + "Member": "Microsoft.EntityFrameworkCore.Infrastructure.StructuredJsonPath? JsonPath { get; }" }, { "Member": "string? OriginalParameterName { get; }" @@ -6209,7 +6209,7 @@ "Member": "Microsoft.EntityFrameworkCore.Metadata.IRelationalJsonElement? ParentElement { get; }" }, { - "Member": "System.Collections.Generic.IReadOnlyList Path { get; }" + "Member": "System.Collections.Generic.IReadOnlyList Path { get; }" }, { "Member": "System.Collections.Generic.IReadOnlyList PropertyMappings { get; }" @@ -7326,10 +7326,10 @@ ] }, { - "Type": "class Microsoft.EntityFrameworkCore.Infrastructure.JsonPath", + "Type": "class Microsoft.EntityFrameworkCore.Infrastructure.StructuredJsonPath", "Methods": [ { - "Member": "JsonPath(System.Collections.Generic.IReadOnlyList segments, int[] ordinals);" + "Member": "StructuredJsonPath(System.Collections.Generic.IReadOnlyList segments, int[] indices);" }, { "Member": "virtual System.Text.StringBuilder AppendTo(System.Text.StringBuilder builder);" @@ -7343,21 +7343,21 @@ "Member": "virtual bool IsRoot { get; }" }, { - "Member": "virtual int[] Ordinals { get; }" + "Member": "virtual int[] Indices { get; }" }, { - "Member": "static Microsoft.EntityFrameworkCore.Infrastructure.JsonPath Root { get; }" + "Member": "static Microsoft.EntityFrameworkCore.Infrastructure.StructuredJsonPath Root { get; }" }, { - "Member": "virtual System.Collections.Generic.IReadOnlyList Segments { get; }" + "Member": "virtual System.Collections.Generic.IReadOnlyList Segments { get; }" } ] }, { - "Type": "sealed class Microsoft.EntityFrameworkCore.Infrastructure.JsonPathSegment", + "Type": "sealed class Microsoft.EntityFrameworkCore.Metadata.StructuredJsonPathSegment", "Methods": [ { - "Member": "JsonPathSegment(string propertyName);" + "Member": "StructuredJsonPathSegment(string propertyName);" }, { "Member": "override string ToString();" @@ -7365,7 +7365,7 @@ ], "Properties": [ { - "Member": "static Microsoft.EntityFrameworkCore.Infrastructure.JsonPathSegment Array { get; }" + "Member": "static Microsoft.EntityFrameworkCore.Metadata.StructuredJsonPathSegment Array { get; }" }, { "Member": "bool IsArray { get; }" @@ -8466,7 +8466,7 @@ ], "Properties": [ { - "Member": "virtual string? LatestMigrationId { get; }" + "Member": "virtual string? LastMigrationId { get; }" }, { "Member": "virtual Microsoft.EntityFrameworkCore.Metadata.IModel Model { get; }" diff --git a/src/EFCore.Relational/Infrastructure/ModelSnapshot.cs b/src/EFCore.Relational/Infrastructure/ModelSnapshot.cs index d98421b7c9e..9cf5fc0a7eb 100644 --- a/src/EFCore.Relational/Infrastructure/ModelSnapshot.cs +++ b/src/EFCore.Relational/Infrastructure/ModelSnapshot.cs @@ -34,7 +34,7 @@ public virtual IModel Model /// /// See Database migrations for more information and examples. /// - public virtual string? LatestMigrationId + public virtual string? LastMigrationId => null; /// diff --git a/src/EFCore.Relational/Infrastructure/JsonPath.cs b/src/EFCore.Relational/Infrastructure/StructuredJsonPath.cs similarity index 60% rename from src/EFCore.Relational/Infrastructure/JsonPath.cs rename to src/EFCore.Relational/Infrastructure/StructuredJsonPath.cs index 340981691e5..8d094f952cd 100644 --- a/src/EFCore.Relational/Infrastructure/JsonPath.cs +++ b/src/EFCore.Relational/Infrastructure/StructuredJsonPath.cs @@ -2,55 +2,56 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text; +using Microsoft.EntityFrameworkCore.Metadata; namespace Microsoft.EntityFrameworkCore.Infrastructure; /// /// Represents a structured JSON path consisting of property name segments and array index placeholders, -/// along with runtime ordinal values for array positions. +/// along with runtime index values for array positions. /// /// /// See Modeling entity types and relationships for more information and examples. /// -public class JsonPath +public class StructuredJsonPath { /// - /// A representing the root of a JSON document ($). + /// A representing the root of a JSON document ($). /// - public static JsonPath Root { get; } = new([], []); + public static StructuredJsonPath Root { get; } = new([], []); /// - /// Creates a new instance. + /// Creates a new instance. /// /// The path segments. - /// - /// The ordinal values for array index placeholders. Must have one entry for each segment - /// where is . + /// + /// The index values for array index placeholders. Must have one entry for each segment + /// where is . /// - public JsonPath(IReadOnlyList segments, int[] ordinals) + public StructuredJsonPath(IReadOnlyList segments, int[] indices) { var arraySegmentCount = segments.Count(s => s.IsArray); - if (ordinals.Length != arraySegmentCount) + if (indices.Length != arraySegmentCount) { throw new ArgumentException( - CoreStrings.InvalidJsonPathOrdinalCount(ordinals.Length, arraySegmentCount), - nameof(ordinals)); + CoreStrings.InvalidStructuredJsonPathIndexCount(indices.Length, arraySegmentCount), + nameof(indices)); } Segments = segments; - Ordinals = ordinals; + Indices = indices; } /// /// Gets the path segments. /// - public virtual IReadOnlyList Segments { get; } + public virtual IReadOnlyList Segments { get; } /// - /// Gets the ordinal values for array index placeholders. The ordinals are applied in order - /// to the segments where is . + /// Gets the index values for array index placeholders. The indices are applied in order + /// to the segments where is . /// - public virtual int[] Ordinals { get; } + public virtual int[] Indices { get; } /// /// Gets a value indicating whether this path represents the root of a JSON document ($). @@ -67,13 +68,13 @@ public virtual StringBuilder AppendTo(StringBuilder builder) { builder.Append('$'); - var ordinalIndex = 0; + var indexPosition = 0; foreach (var segment in Segments) { if (segment.IsArray) { builder.Append('['); - builder.Append(Ordinals[ordinalIndex++]); + builder.Append(Indices[indexPosition++]); builder.Append(']'); } else diff --git a/src/EFCore.Relational/Metadata/IRelationalJsonElement.cs b/src/EFCore.Relational/Metadata/IRelationalJsonElement.cs index b2fc07037ad..ffb85679a08 100644 --- a/src/EFCore.Relational/Metadata/IRelationalJsonElement.cs +++ b/src/EFCore.Relational/Metadata/IRelationalJsonElement.cs @@ -29,7 +29,7 @@ public interface IRelationalJsonElement /// /// Gets the path segments from the root of the JSON document to this element. /// - IReadOnlyList Path { get; } + IReadOnlyList Path { get; } /// /// Gets the parent element, or if this is a root element. diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalJsonElement.cs b/src/EFCore.Relational/Metadata/Internal/RelationalJsonElement.cs index ed946c49e2e..5252f4a24c6 100644 --- a/src/EFCore.Relational/Metadata/Internal/RelationalJsonElement.cs +++ b/src/EFCore.Relational/Metadata/Internal/RelationalJsonElement.cs @@ -57,7 +57,7 @@ protected RelationalJsonElement( bool isNullable) { ContainingColumn = parentElement.ContainingColumn; - Path = [.. parentElement.Path, JsonPathSegment.Array]; + Path = [.. parentElement.Path, StructuredJsonPathSegment.Array]; ParentElement = parentElement; IsNullable = isNullable; } @@ -73,7 +73,7 @@ public virtual RelationalTypeMapping? StoreTypeMapping => GetDefaultStoreTypeMapping(); /// - public virtual IReadOnlyList Path { get; protected set; } + public virtual IReadOnlyList Path { get; protected set; } /// public virtual IRelationalJsonElement? ParentElement { get; } diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalJsonObject.cs b/src/EFCore.Relational/Metadata/Internal/RelationalJsonObject.cs index c30202a031b..5a599bbae8a 100644 --- a/src/EFCore.Relational/Metadata/Internal/RelationalJsonObject.cs +++ b/src/EFCore.Relational/Metadata/Internal/RelationalJsonObject.cs @@ -59,15 +59,15 @@ public RelationalJsonObject( /// 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. /// - public virtual IReadOnlyList CreateChildPath(string childName) + public virtual IReadOnlyList CreateChildPath(string childName) { - var path = new JsonPathSegment[Path.Count + 1]; + var path = new StructuredJsonPathSegment[Path.Count + 1]; for (var i = 0; i < Path.Count; i++) { path[i] = Path[i]; } - path[^1] = new JsonPathSegment(childName); + path[^1] = new StructuredJsonPathSegment(childName); return path; } diff --git a/src/EFCore.Relational/Infrastructure/JsonPathSegment.cs b/src/EFCore.Relational/Metadata/StructuredJsonPathSegment.cs similarity index 73% rename from src/EFCore.Relational/Infrastructure/JsonPathSegment.cs rename to src/EFCore.Relational/Metadata/StructuredJsonPathSegment.cs index dcdf4861efa..372a2c79ee2 100644 --- a/src/EFCore.Relational/Infrastructure/JsonPathSegment.cs +++ b/src/EFCore.Relational/Metadata/StructuredJsonPathSegment.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.EntityFrameworkCore.Infrastructure; +namespace Microsoft.EntityFrameworkCore.Metadata; /// /// Represents a single segment in a JSON path. A segment is either a property name or an array index placeholder. @@ -9,13 +9,13 @@ namespace Microsoft.EntityFrameworkCore.Infrastructure; /// /// See Modeling entity types and relationships for more information and examples. /// -public sealed class JsonPathSegment +public sealed class StructuredJsonPathSegment { /// - /// Creates a new for a named property. + /// Creates a new for a named property. /// /// The JSON property name. - public JsonPathSegment(string propertyName) + public StructuredJsonPathSegment(string propertyName) { Check.NotEmpty(propertyName, nameof(propertyName)); @@ -23,17 +23,17 @@ public JsonPathSegment(string propertyName) IsArray = false; } - private JsonPathSegment(bool isArray) + private StructuredJsonPathSegment(bool isArray) { PropertyName = null; IsArray = isArray; } /// - /// Creates a new for an array index placeholder. + /// Creates a new for an array index placeholder. /// /// A new array index placeholder segment. - public static JsonPathSegment Array { get; } = new(isArray: true); + public static StructuredJsonPathSegment Array { get; } = new(isArray: true); /// /// Gets the JSON property name. for array index placeholder segments. diff --git a/src/EFCore.Relational/Update/ColumnModification.cs b/src/EFCore.Relational/Update/ColumnModification.cs index a8e3ae3121a..7b8147e756b 100644 --- a/src/EFCore.Relational/Update/ColumnModification.cs +++ b/src/EFCore.Relational/Update/ColumnModification.cs @@ -254,7 +254,7 @@ public static bool IsStoreGenerated(IUpdateEntry entry, IProperty property) => entry.IsStoreGenerated(property); /// - public virtual JsonPath? JsonPath { get; } + public virtual StructuredJsonPath? JsonPath { get; } /// public virtual void AddSharedColumnModification(IColumnModification modification) diff --git a/src/EFCore.Relational/Update/ColumnModificationParameters.cs b/src/EFCore.Relational/Update/ColumnModificationParameters.cs index 279ab29f5ef..05483d63d21 100644 --- a/src/EFCore.Relational/Update/ColumnModificationParameters.cs +++ b/src/EFCore.Relational/Update/ColumnModificationParameters.cs @@ -95,7 +95,7 @@ public readonly record struct ColumnModificationParameters /// /// In case of JSON column modification, the JSON path leading to the JSON element that needs to be updated. /// - public JsonPath? JsonPath { get; init; } + public StructuredJsonPath? JsonPath { get; init; } /// /// Creates a new instance. @@ -259,7 +259,7 @@ public ColumnModificationParameters( IProperty? property, string? columnType, RelationalTypeMapping? typeMapping, - JsonPath jsonPath, + StructuredJsonPath jsonPath, bool read, bool write, bool key, diff --git a/src/EFCore.Relational/Update/IColumnModification.cs b/src/EFCore.Relational/Update/IColumnModification.cs index 89736282c61..8fae436bef9 100644 --- a/src/EFCore.Relational/Update/IColumnModification.cs +++ b/src/EFCore.Relational/Update/IColumnModification.cs @@ -128,7 +128,7 @@ public interface IColumnModification /// /// In case of JSON column modification, the JSON path leading to the JSON element that needs to be updated. /// - public JsonPath? JsonPath { get; } + public StructuredJsonPath? JsonPath { get; } /// /// Adds a modification affecting the same database value. diff --git a/src/EFCore.Relational/Update/ModificationCommand.cs b/src/EFCore.Relational/Update/ModificationCommand.cs index 5ffac6fd252..975a981641e 100644 --- a/src/EFCore.Relational/Update/ModificationCommand.cs +++ b/src/EFCore.Relational/Update/ModificationCommand.cs @@ -792,7 +792,7 @@ void HandleJson(List columnModifications) ? ordinals.GetRange(0, arraySegmentCount).ToArray() : ordinals.ToArray(); - var jsonPath = new JsonPath(pathSegments, ordinalsArray); + var jsonPath = new StructuredJsonPath(pathSegments, ordinalsArray); if (jsonProperty is IProperty property) { var columnModificationParameters = new ColumnModificationParameters( diff --git a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs index b11f4d65297..171ff92845c 100644 --- a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs +++ b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs @@ -267,7 +267,7 @@ private static string CompiledModelProviderMismatch(EventDefinitionBase definiti { var d = (EventDefinition)definition; var p = (ProviderMismatchEventData)payload; - return d.GenerateMessage(p.CompiledProviderName, p.CurrentProviderName); + return d.GenerateMessage(p.MismatchedProviderName, p.CurrentProviderName); } /// diff --git a/src/EFCore/Diagnostics/ProviderMismatchEventData.cs b/src/EFCore/Diagnostics/ProviderMismatchEventData.cs index 4501cbc536d..519be678b5d 100644 --- a/src/EFCore/Diagnostics/ProviderMismatchEventData.cs +++ b/src/EFCore/Diagnostics/ProviderMismatchEventData.cs @@ -16,23 +16,23 @@ public class ProviderMismatchEventData : EventData /// /// The event definition. /// A delegate that generates a log message for this event. - /// The provider name stored with the model. + /// The provider name stored with the model. /// The provider name currently configured. public ProviderMismatchEventData( EventDefinitionBase eventDefinition, Func messageGenerator, - string compiledProviderName, + string mismatchedProviderName, string currentProviderName) : base(eventDefinition, messageGenerator) { - CompiledProviderName = compiledProviderName; + MismatchedProviderName = mismatchedProviderName; CurrentProviderName = currentProviderName; } /// /// The provider name stored with the model. /// - public virtual string CompiledProviderName { get; } + public virtual string MismatchedProviderName { get; } /// /// The provider name currently configured. diff --git a/src/EFCore/EFCore.baseline.json b/src/EFCore/EFCore.baseline.json index 24e1fc07293..2a7ac2fbcb6 100644 --- a/src/EFCore/EFCore.baseline.json +++ b/src/EFCore/EFCore.baseline.json @@ -4152,7 +4152,7 @@ "Member": "static string InvalidIncludeExpression(object? expression);" }, { - "Member": "static string InvalidJsonPathOrdinalCount(object? ordinalsCount, object? arraySegmentCount);" + "Member": "static string InvalidStructuredJsonPathIndexCount(object? indicesCount, object? arraySegmentCount);" }, { "Member": "static string InvalidKeyValue(object? entityType, object? keyProperty);" @@ -20840,7 +20840,7 @@ ], "Properties": [ { - "Member": "virtual string CompiledProviderName { get; }" + "Member": "virtual string MismatchedProviderName { get; }" }, { "Member": "virtual string CurrentProviderName { get; }" diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs index 918ccec6adc..6e8f823dc59 100644 --- a/src/EFCore/Properties/CoreStrings.Designer.cs +++ b/src/EFCore/Properties/CoreStrings.Designer.cs @@ -1758,12 +1758,12 @@ public static string InvalidIncludeExpression(object? expression) expression); /// - /// The number of ordinals provided ({ordinalsCount}) must match the number of array segments in the JSON path ({arraySegmentCount}). + /// The number of indices provided ({indicesCount}) must match the number of array segments in the JSON path ({arraySegmentCount}). /// - public static string InvalidJsonPathOrdinalCount(object? ordinalsCount, object? arraySegmentCount) + public static string InvalidStructuredJsonPathIndexCount(object? indicesCount, object? arraySegmentCount) => string.Format( - GetString("InvalidJsonPathOrdinalCount", nameof(ordinalsCount), nameof(arraySegmentCount)), - ordinalsCount, arraySegmentCount); + GetString("InvalidStructuredJsonPathIndexCount", nameof(indicesCount), nameof(arraySegmentCount)), + indicesCount, arraySegmentCount); /// /// Unable to track an entity of type '{entityType}' because its primary key property '{keyProperty}' is null. diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx index 1b2a3fc1494..b2baabea60a 100644 --- a/src/EFCore/Properties/CoreStrings.resx +++ b/src/EFCore/Properties/CoreStrings.resx @@ -781,8 +781,8 @@ The expression '{expression}' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'. To target navigations declared on derived types, use casting ('t => ((Derived)t).MyProperty') or the 'as' operator ('t => (t as Derived).MyProperty'). Collection navigation access can be filtered by composing Where, OrderBy(Descending), ThenBy(Descending), Skip or Take operations. For more information on including related data, see https://go.microsoft.com/fwlink/?LinkID=746393. - - The number of ordinals provided ({ordinalsCount}) must match the number of array segments in the JSON path ({arraySegmentCount}). + + The number of indices provided ({indicesCount}) must match the number of array segments in the JSON path ({arraySegmentCount}). Unable to track an entity of type '{entityType}' because its primary key property '{keyProperty}' is null. diff --git a/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkConcurrencyTest.cs b/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkConcurrencyTest.cs index 721f3b01528..59bc6392de3 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkConcurrencyTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkConcurrencyTest.cs @@ -25,7 +25,7 @@ public override ConcurrencyContext CreateContext() } public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) - => base.AddOptions(builder).UseCosmos(x => x.BulkExecutionEnabled()); + => base.AddOptions(builder).UseCosmos(x => x.BulkExecutionAllowed()); } protected override ConcurrencyContext CreateContext(DbContextOptions options) diff --git a/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkEndToEndTest.cs b/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkEndToEndTest.cs index 789b7d12894..bf43432ceef 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkEndToEndTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkEndToEndTest.cs @@ -6,5 +6,5 @@ namespace Microsoft.EntityFrameworkCore.Update; public class CosmosBulkEndToEndTest(NonSharedFixture fixture) : EndToEndCosmosTest(fixture), IClassFixture { protected override DbContextOptionsBuilder AddNonSharedOptions(DbContextOptionsBuilder builder) - => base.AddNonSharedOptions(builder).UseCosmos(x => x.BulkExecutionEnabled()).ConfigureWarnings(x => x.Ignore(CosmosEventId.BulkExecutionWithTransactionalBatch)); + => base.AddNonSharedOptions(builder).UseCosmos(x => x.BulkExecutionAllowed()).ConfigureWarnings(x => x.Ignore(CosmosEventId.BulkExecutionWithTransactionalBatch)); } diff --git a/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkEndToEndTestNoBatching.cs b/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkEndToEndTestNoBatching.cs index df024e7b508..e97f912b4b7 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkEndToEndTestNoBatching.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkEndToEndTestNoBatching.cs @@ -6,7 +6,7 @@ namespace Microsoft.EntityFrameworkCore.Update; public class CosmosBulkEndToEndTestNoBatching(NonSharedFixture fixture) : EndToEndCosmosTest(fixture), IClassFixture { protected override DbContextOptionsBuilder AddNonSharedOptions(DbContextOptionsBuilder builder) - => base.AddNonSharedOptions(builder).UseCosmos(x => x.BulkExecutionEnabled()); + => base.AddNonSharedOptions(builder).UseCosmos(x => x.BulkExecutionAllowed()); protected override TContext CreateContext(ContextFactory factory, bool transactionalBatch) { diff --git a/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkExecutionTest.cs b/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkExecutionTest.cs index 16cc4424c43..1ce5cc30df7 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkExecutionTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkExecutionTest.cs @@ -14,7 +14,7 @@ public class CosmosBulkExecutionTest(NonSharedFixture fixture) : NonSharedModelT [CosmosCondition(CosmosCondition.IsNotLinuxEmulator)] public virtual async Task DoesNotBatchSingleBatchableWrite() { - var contextFactory = await InitializeNonSharedTest(onConfiguring: (cfg) => cfg.UseCosmos(c => c.BulkExecutionEnabled()).ConfigureWarnings(x => x.Ignore(CosmosEventId.BulkExecutionWithTransactionalBatch))); + var contextFactory = await InitializeNonSharedTest(onConfiguring: (cfg) => cfg.UseCosmos(c => c.BulkExecutionAllowed()).ConfigureWarnings(x => x.Ignore(CosmosEventId.BulkExecutionWithTransactionalBatch))); using var context = contextFactory.CreateDbContext(); context.Add(new Customer() { PartitionKey = "4" }); @@ -34,7 +34,7 @@ public virtual async Task DoesNotBatchSingleBatchableWrite() [ConditionalFact] public async Task SessionEnabled_Throws() { - var contextFactory = await InitializeNonSharedTest(onConfiguring: (cfg) => cfg.UseCosmos(c => c.BulkExecutionEnabled().SessionTokenManagementMode(Cosmos.Infrastructure.SessionTokenManagementMode.SemiAutomatic))); + var contextFactory = await InitializeNonSharedTest(onConfiguring: (cfg) => cfg.UseCosmos(c => c.BulkExecutionAllowed().SessionTokenManagementMode(Cosmos.Infrastructure.SessionTokenManagementMode.SemiAutomatic))); using var context = contextFactory.CreateDbContext(); context.Database.AutoTransactionBehavior = AutoTransactionBehavior.Never; context.Database.UseSessionToken("0:-1#1"); @@ -47,7 +47,7 @@ public async Task SessionEnabled_Throws() [ConditionalFact] public async Task Trigger_Throws() { - var contextFactory = await InitializeNonSharedTest(onModelCreating: (b) => b.Entity().HasTrigger(NonSharedStoreName, Azure.Cosmos.Scripts.TriggerType.Post, Azure.Cosmos.Scripts.TriggerOperation.Create), onConfiguring: (cfg) => cfg.UseCosmos(c => c.BulkExecutionEnabled())); + var contextFactory = await InitializeNonSharedTest(onModelCreating: (b) => b.Entity().HasTrigger(NonSharedStoreName, Azure.Cosmos.Scripts.TriggerType.Post, Azure.Cosmos.Scripts.TriggerOperation.Create), onConfiguring: (cfg) => cfg.UseCosmos(c => c.BulkExecutionAllowed())); using var context = contextFactory.CreateDbContext(); context.Database.AutoTransactionBehavior = AutoTransactionBehavior.Never; context.Add(new Customer()); @@ -85,6 +85,6 @@ protected override string StoreName protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance; - public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) => base.AddOptions(builder).UseCosmos(x => x.BulkExecutionEnabled()).ConfigureWarnings(x => x.Ignore(CosmosEventId.BulkExecutionWithTransactionalBatch)); + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) => base.AddOptions(builder).UseCosmos(x => x.BulkExecutionAllowed()).ConfigureWarnings(x => x.Ignore(CosmosEventId.BulkExecutionWithTransactionalBatch)); } } diff --git a/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkWarningTest.cs b/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkWarningTest.cs index f1adfa45dbf..30729e11826 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkWarningTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Update/CosmosBulkWarningTest.cs @@ -58,6 +58,6 @@ protected override string StoreName protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance; - public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) => base.AddOptions(builder).UseCosmos(x => x.BulkExecutionEnabled()); + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) => base.AddOptions(builder).UseCosmos(x => x.BulkExecutionAllowed()); } } diff --git a/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs b/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs index 79e7571f4e1..d7afe29cee0 100644 --- a/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs +++ b/test/EFCore.Cosmos.Tests/Extensions/CosmosDbContextOptionsExtensionsTests.cs @@ -68,7 +68,7 @@ public void Can_create_options_with_valid_values() Test(o => o.ContentResponseOnWriteEnabled(), o => Assert.True(o.EnableContentResponseOnWrite)); #pragma warning restore CS0618 // Type or member is obsolete Test(o => o.SessionTokenManagementMode(Cosmos.Infrastructure.SessionTokenManagementMode.EnforcedManual), o => Assert.Equal(Cosmos.Infrastructure.SessionTokenManagementMode.EnforcedManual, o.SessionTokenManagementMode)); - Test(o => o.BulkExecutionEnabled(), o => Assert.True(o.EnableBulkExecution)); + Test(o => o.BulkExecutionAllowed(), o => Assert.True(o.EnableBulkExecution)); var webProxy = new WebProxy(); Test(o => o.WebProxy(webProxy), o => Assert.Same(webProxy, o.WebProxy)); diff --git a/test/EFCore.Design.Tests/Design/OperationExecutorTest.cs b/test/EFCore.Design.Tests/Design/OperationExecutorTest.cs index ce4950822a0..f31636b8cf7 100644 --- a/test/EFCore.Design.Tests/Design/OperationExecutorTest.cs +++ b/test/EFCore.Design.Tests/Design/OperationExecutorTest.cs @@ -184,7 +184,7 @@ partial class GnomeContextModelSnapshot : ModelSnapshot // If you encounter a merge conflict in the line below, it means you need to // discard one of the migration branches and recreate its migrations on top of // the other branch. See https://aka.ms/efcore-docs-migrations-conflicts for more info. - public override string LatestMigrationId => "11112233445566_{{migrationName}}"; + public override string LastMigrationId => "11112233445566_{{migrationName}}"; protected override void BuildModel(ModelBuilder modelBuilder) { diff --git a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs index 145e0c2fd26..e7f82aaa97b 100644 --- a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs +++ b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs @@ -142,14 +142,14 @@ public void Snapshot_with_migration_id() finalizedModel, "20240101120000_InitialCreate"); - Assert.Contains("public override string LatestMigrationId => \"20240101120000_InitialCreate\";", modelSnapshotCode); + Assert.Contains("public override string LastMigrationId => \"20240101120000_InitialCreate\";", modelSnapshotCode); Assert.Contains("// If you encounter a merge conflict in the line below, it means you need to", modelSnapshotCode); Assert.Contains("// discard one of the migration branches and recreate its migrations on top of", modelSnapshotCode); Assert.Contains("// the other branch. See https://aka.ms/efcore-docs-migrations-conflicts for more info.", modelSnapshotCode); var snapshot = CompileModelSnapshot(modelSnapshotCode, "MyNamespace.MySnapshot", typeof(MyContext)); Assert.NotNull(snapshot.Model); - Assert.Equal("20240101120000_InitialCreate", snapshot.LatestMigrationId); + Assert.Equal("20240101120000_InitialCreate", snapshot.LastMigrationId); } [ConditionalFact] @@ -171,12 +171,12 @@ public void Snapshot_without_migration_id() "MySnapshot", finalizedModel); - Assert.DoesNotContain("LatestMigrationId", modelSnapshotCode); + Assert.DoesNotContain("LastMigrationId", modelSnapshotCode); Assert.DoesNotContain("merge conflict", modelSnapshotCode); var snapshot = CompileModelSnapshot(modelSnapshotCode, "MyNamespace.MySnapshot", typeof(MyContext)); Assert.NotNull(snapshot.Model); - Assert.Null(snapshot.LatestMigrationId); + Assert.Null(snapshot.LastMigrationId); } [ConditionalFact] diff --git a/test/EFCore.SqlServer.HierarchyId.Tests/TestModels/Migrations/AnonymousArraySeedContext.cs b/test/EFCore.SqlServer.HierarchyId.Tests/TestModels/Migrations/AnonymousArraySeedContext.cs index 856e1e42d1e..20e64e380c9 100644 --- a/test/EFCore.SqlServer.HierarchyId.Tests/TestModels/Migrations/AnonymousArraySeedContext.cs +++ b/test/EFCore.SqlServer.HierarchyId.Tests/TestModels/Migrations/AnonymousArraySeedContext.cs @@ -134,7 +134,7 @@ partial class {ThisType.Name}ModelSnapshot : ModelSnapshot // If you encounter a merge conflict in the line below, it means you need to // discard one of the migration branches and recreate its migrations on top of // the other branch. See https://aka.ms/efcore-docs-migrations-conflicts for more info. - public override string LatestMigrationId => ""{migrationId}""; + public override string LastMigrationId => ""{migrationId}""; protected override void BuildModel(ModelBuilder modelBuilder) {{ diff --git a/test/EFCore.SqlServer.HierarchyId.Tests/TestModels/Migrations/TypedArraySeedContext.cs b/test/EFCore.SqlServer.HierarchyId.Tests/TestModels/Migrations/TypedArraySeedContext.cs index 741c61dc3b6..83302755836 100644 --- a/test/EFCore.SqlServer.HierarchyId.Tests/TestModels/Migrations/TypedArraySeedContext.cs +++ b/test/EFCore.SqlServer.HierarchyId.Tests/TestModels/Migrations/TypedArraySeedContext.cs @@ -134,7 +134,7 @@ partial class {ThisType.Name}ModelSnapshot : ModelSnapshot // If you encounter a merge conflict in the line below, it means you need to // discard one of the migration branches and recreate its migrations on top of // the other branch. See https://aka.ms/efcore-docs-migrations-conflicts for more info. - public override string LatestMigrationId => ""{migrationId}""; + public override string LastMigrationId => ""{migrationId}""; protected override void BuildModel(ModelBuilder modelBuilder) {{ diff --git a/test/EFCore.Tests/Infrastructure/JsonPathTest.cs b/test/EFCore.Tests/Infrastructure/JsonPathTest.cs deleted file mode 100644 index cb68de68881..00000000000 --- a/test/EFCore.Tests/Infrastructure/JsonPathTest.cs +++ /dev/null @@ -1,112 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.EntityFrameworkCore.Infrastructure; - -public class JsonPathTest -{ - [ConditionalFact] - public void JsonPathSegment_property_name() - { - var segment = new JsonPathSegment("Name"); - Assert.Equal("Name", segment.PropertyName); - Assert.False(segment.IsArray); - Assert.Equal("Name", segment.ToString()); - } - - [ConditionalFact] - public void JsonPathSegment_array() - { - var segment = JsonPathSegment.Array; - Assert.Null(segment.PropertyName); - Assert.True(segment.IsArray); - Assert.Equal("[]", segment.ToString()); - } - - [ConditionalFact] - public void JsonPathSegment_empty_name_throws() - { - Assert.Throws(() => new JsonPathSegment("")); - } - - [ConditionalFact] - public void JsonPath_root() - { - var path = JsonPath.Root; - Assert.True(path.IsRoot); - Assert.Empty(path.Segments); - Assert.Empty(path.Ordinals); - Assert.Equal("$", path.ToString()); - } - - [ConditionalFact] - public void JsonPath_simple_property() - { - var path = new JsonPath([new JsonPathSegment("Address")], []); - Assert.False(path.IsRoot); - Assert.Equal("$.Address", path.ToString()); - } - - [ConditionalFact] - public void JsonPath_nested_properties() - { - var path = new JsonPath( - [new JsonPathSegment("Address"), new JsonPathSegment("City")], - []); - Assert.Equal("$.Address.City", path.ToString()); - } - - [ConditionalFact] - public void JsonPath_root_array_index() - { - var path = new JsonPath( - [JsonPathSegment.Array, new JsonPathSegment("Name")], - [3]); - Assert.Equal("$[3].Name", path.ToString()); - } - - [ConditionalFact] - public void JsonPath_with_array_index() - { - var path = new JsonPath( - [new JsonPathSegment("Items"), JsonPathSegment.Array, new JsonPathSegment("Name")], - [3]); - Assert.Equal("$.Items[3].Name", path.ToString()); - } - - [ConditionalFact] - public void JsonPath_with_multiple_array_indices() - { - var path = new JsonPath( - [ - new JsonPathSegment("Orders"), - JsonPathSegment.Array, - new JsonPathSegment("Items"), - JsonPathSegment.Array, - new JsonPathSegment("Name") - ], - [1, 2]); - Assert.Equal("$.Orders[1].Items[2].Name", path.ToString()); - } - - [ConditionalFact] - public void JsonPath_array_only() - { - var path = new JsonPath( - [new JsonPathSegment("Items"), JsonPathSegment.Array], - [0]); - Assert.Equal("$.Items[0]", path.ToString()); - } - - [ConditionalFact] - public void JsonPath_AppendTo_builds_same_as_ToString() - { - var path = new JsonPath( - [new JsonPathSegment("A"), JsonPathSegment.Array, new JsonPathSegment("B")], - [5]); - - var sb = new System.Text.StringBuilder(); - path.AppendTo(sb); - Assert.Equal(path.ToString(), sb.ToString()); - } -} diff --git a/test/EFCore.Tests/Infrastructure/StructuredJsonPathTest.cs b/test/EFCore.Tests/Infrastructure/StructuredJsonPathTest.cs new file mode 100644 index 00000000000..a80f23ad89b --- /dev/null +++ b/test/EFCore.Tests/Infrastructure/StructuredJsonPathTest.cs @@ -0,0 +1,114 @@ +// 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; + +namespace Microsoft.EntityFrameworkCore.Infrastructure; + +public class StructuredJsonPathTest +{ + [ConditionalFact] + public void StructuredJsonPathSegment_property_name() + { + var segment = new StructuredJsonPathSegment("Name"); + Assert.Equal("Name", segment.PropertyName); + Assert.False(segment.IsArray); + Assert.Equal("Name", segment.ToString()); + } + + [ConditionalFact] + public void StructuredJsonPathSegment_array() + { + var segment = StructuredJsonPathSegment.Array; + Assert.Null(segment.PropertyName); + Assert.True(segment.IsArray); + Assert.Equal("[]", segment.ToString()); + } + + [ConditionalFact] + public void StructuredJsonPathSegment_empty_name_throws() + { + Assert.Throws(() => new StructuredJsonPathSegment("")); + } + + [ConditionalFact] + public void StructuredJsonPath_root() + { + var path = StructuredJsonPath.Root; + Assert.True(path.IsRoot); + Assert.Empty(path.Segments); + Assert.Empty(path.Indices); + Assert.Equal("$", path.ToString()); + } + + [ConditionalFact] + public void StructuredJsonPath_simple_property() + { + var path = new StructuredJsonPath([new StructuredJsonPathSegment("Address")], []); + Assert.False(path.IsRoot); + Assert.Equal("$.Address", path.ToString()); + } + + [ConditionalFact] + public void StructuredJsonPath_nested_properties() + { + var path = new StructuredJsonPath( + [new StructuredJsonPathSegment("Address"), new StructuredJsonPathSegment("City")], + []); + Assert.Equal("$.Address.City", path.ToString()); + } + + [ConditionalFact] + public void StructuredJsonPath_root_array_index() + { + var path = new StructuredJsonPath( + [StructuredJsonPathSegment.Array, new StructuredJsonPathSegment("Name")], + [3]); + Assert.Equal("$[3].Name", path.ToString()); + } + + [ConditionalFact] + public void StructuredJsonPath_with_array_index() + { + var path = new StructuredJsonPath( + [new StructuredJsonPathSegment("Items"), StructuredJsonPathSegment.Array, new StructuredJsonPathSegment("Name")], + [3]); + Assert.Equal("$.Items[3].Name", path.ToString()); + } + + [ConditionalFact] + public void StructuredJsonPath_with_multiple_array_indices() + { + var path = new StructuredJsonPath( + [ + new StructuredJsonPathSegment("Orders"), + StructuredJsonPathSegment.Array, + new StructuredJsonPathSegment("Items"), + StructuredJsonPathSegment.Array, + new StructuredJsonPathSegment("Name") + ], + [1, 2]); + Assert.Equal("$.Orders[1].Items[2].Name", path.ToString()); + } + + [ConditionalFact] + public void StructuredJsonPath_array_only() + { + var path = new StructuredJsonPath( + [new StructuredJsonPathSegment("Items"), StructuredJsonPathSegment.Array], + [0]); + Assert.Equal("$.Items[0]", path.ToString()); + } + + [ConditionalFact] + public void StructuredJsonPath_AppendTo_builds_same_as_ToString() + { + var path = new StructuredJsonPath( + [new StructuredJsonPathSegment("A"), StructuredJsonPathSegment.Array, new StructuredJsonPathSegment("B")], + [5]); + + var sb = new System.Text.StringBuilder(); + path.AppendTo(sb); + Assert.Equal(path.ToString(), sb.ToString()); + } +} From 6a88d7a1d3a81b08aaaccdefdfa90a213de3db39 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Apr 2026 04:31:11 +0000 Subject: [PATCH 2/3] Fix EFCore baseline for ProviderMismatchEventData constructor parameter rename Agent-Logs-Url: https://github.com/dotnet/efcore/sessions/56ecc586-e9c8-4c70-8a17-fbcaaed4a258 Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- src/EFCore/EFCore.baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EFCore/EFCore.baseline.json b/src/EFCore/EFCore.baseline.json index 2a7ac2fbcb6..57ed67e9cdd 100644 --- a/src/EFCore/EFCore.baseline.json +++ b/src/EFCore/EFCore.baseline.json @@ -20835,7 +20835,7 @@ "Type": "class Microsoft.EntityFrameworkCore.Diagnostics.ProviderMismatchEventData : Microsoft.EntityFrameworkCore.Diagnostics.EventData", "Methods": [ { - "Member": "ProviderMismatchEventData(Microsoft.EntityFrameworkCore.Diagnostics.EventDefinitionBase eventDefinition, System.Func messageGenerator, string compiledProviderName, string currentProviderName);" + "Member": "ProviderMismatchEventData(Microsoft.EntityFrameworkCore.Diagnostics.EventDefinitionBase eventDefinition, System.Func messageGenerator, string mismatchedProviderName, string currentProviderName);" } ], "Properties": [ From facc999370033bb1ac27a290647a8deef6f92cf4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Apr 2026 01:47:49 +0000 Subject: [PATCH 3/3] Rename ordinalsArray to indicesArray in ModificationCommand.cs Agent-Logs-Url: https://github.com/dotnet/efcore/sessions/4a245278-1478-40ef-83bd-57a2b44e7c0a Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- src/EFCore.Relational/Update/ModificationCommand.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EFCore.Relational/Update/ModificationCommand.cs b/src/EFCore.Relational/Update/ModificationCommand.cs index 975a981641e..2df1ca244a4 100644 --- a/src/EFCore.Relational/Update/ModificationCommand.cs +++ b/src/EFCore.Relational/Update/ModificationCommand.cs @@ -788,11 +788,11 @@ void HandleJson(List columnModifications) // FindCommonJsonPartialUpdateInfo may have reduced the update to a common ancestor // that has fewer array levels than the originally collected ordinals. var arraySegmentCount = pathSegments.Count(s => s.IsArray); - var ordinalsArray = ordinals.Count > arraySegmentCount + var indicesArray = ordinals.Count > arraySegmentCount ? ordinals.GetRange(0, arraySegmentCount).ToArray() : ordinals.ToArray(); - var jsonPath = new StructuredJsonPath(pathSegments, ordinalsArray); + var jsonPath = new StructuredJsonPath(pathSegments, indicesArray); if (jsonProperty is IProperty property) { var columnModificationParameters = new ColumnModificationParameters(