From 63b1e0a966273701b4b7346ef21defda74782424 Mon Sep 17 00:00:00 2001 From: Brice Lambson Date: Fri, 8 Sep 2023 16:17:25 -0700 Subject: [PATCH 1/4] Migrations: Fix ComplexPropertyBuilder.IsRequired call in snapshot (#31666) Fixes #31665, resolves #31414 --- .../Design/CSharpSnapshotGenerator.cs | 3 +- .../Migrations/ModelSnapshotSqlServerTest.cs | 65 +++++++++++++++++-- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs index 7092724682c..365a06a3f97 100644 --- a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs +++ b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs @@ -576,7 +576,8 @@ protected virtual void GenerateComplexProperty( { stringBuilder .AppendLine() - .Append(".IsRequired()"); + .Append(complexTypeBuilderName) + .AppendLine(".IsRequired();"); } GenerateProperties(complexTypeBuilderName, complexType.GetDeclaredProperties(), stringBuilder); diff --git a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs index dc5f28bf12b..e8d7423f232 100644 --- a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs +++ b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs @@ -7,7 +7,6 @@ using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Migrations.Internal; using Microsoft.EntityFrameworkCore.SqlServer.Design.Internal; -using Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal; using Microsoft.EntityFrameworkCore.SqlServer.Metadata.Internal; using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal; using NetTopologySuite; @@ -66,6 +65,12 @@ private class EntityWithManyProperties public MultiPolygon SpatialCMultiPolygon { get; set; } public Point SpatialCPoint { get; set; } public Polygon SpatialCPolygon { get; set; } + public int[] Int32Collection { get; set; } + public double[] DoubleCollection { get; set; } + public string[] StringCollection { get; set; } + public DateTime[] DateTimeCollection { get; set; } + public bool[] BoolCollection { get; set; } + public byte[][] BytesCollection { get; set; } } private enum Enum64 : long @@ -5452,8 +5457,11 @@ public virtual void Complex_properties_are_stored_in_snapshot() { b.ComplexProperty(eo => eo.EntityWithTwoProperties, eb => { + eb.IsRequired(); eb.Property(e => e.AlternateId).HasColumnOrder(1); - eb.ComplexProperty(e => e.EntityWithStringKey); + eb.ComplexProperty(e => e.EntityWithStringKey).IsRequired(); + eb.HasPropertyAnnotation("PropertyAnnotation", 1); + eb.HasTypeAnnotation("TypeAnnotation", 2); }); }); }, @@ -5470,6 +5478,8 @@ public virtual void Complex_properties_are_stored_in_snapshot() b.ComplexProperty>("EntityWithTwoProperties", "Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+EntityWithOneProperty.EntityWithTwoProperties#EntityWithTwoProperties", b1 => { + b1.IsRequired(); + b1.Property("AlternateId") .HasColumnType("int") .HasColumnOrder(1); @@ -5479,9 +5489,15 @@ public virtual void Complex_properties_are_stored_in_snapshot() b1.ComplexProperty>("EntityWithStringKey", "Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+EntityWithOneProperty.EntityWithTwoProperties#EntityWithTwoProperties.EntityWithStringKey#EntityWithStringKey", b2 => { + b2.IsRequired(); + b2.Property("Id") .HasColumnType("nvarchar(max)"); }); + + b1.HasPropertyAnnotation("PropertyAnnotation", 1); + + b1.HasTypeAnnotation("TypeAnnotation", 2); }); b.HasKey("Id"); @@ -5496,17 +5512,19 @@ public virtual void Complex_properties_are_stored_in_snapshot() var complexProperty = entityWithOneProperty.FindComplexProperty(nameof(EntityWithOneProperty.EntityWithTwoProperties)); Assert.False(complexProperty.IsCollection); - Assert.True(complexProperty.IsNullable); + Assert.False(complexProperty.IsNullable); var complexType = complexProperty.ComplexType; Assert.Equal("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+EntityWithOneProperty.EntityWithTwoProperties#EntityWithTwoProperties", complexType.Name); Assert.Equal("EntityWithOneProperty.EntityWithTwoProperties#EntityWithTwoProperties", complexType.DisplayName()); Assert.Equal(nameof(EntityWithOneProperty), complexType.GetTableName()); var alternateIdProperty = complexType.FindProperty(nameof(EntityWithTwoProperties.AlternateId)); Assert.Equal(1, alternateIdProperty.GetColumnOrder()); + Assert.Equal(1, complexProperty["PropertyAnnotation"]); + Assert.Equal(2, complexProperty.ComplexType["TypeAnnotation"]); var nestedComplexProperty = complexType.FindComplexProperty(nameof(EntityWithTwoProperties.EntityWithStringKey)); Assert.False(nestedComplexProperty.IsCollection); - Assert.True(nestedComplexProperty.IsNullable); + Assert.False(nestedComplexProperty.IsNullable); var nestedComplexType = nestedComplexProperty.ComplexType; Assert.Equal("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+EntityWithOneProperty.EntityWithTwoProperties#EntityWithTwoProperties.EntityWithStringKey#EntityWithStringKey", nestedComplexType.Name); Assert.Equal("EntityWithOneProperty.EntityWithTwoProperties#EntityWithTwoProperties.EntityWithStringKey#EntityWithStringKey", nestedComplexType.DisplayName()); @@ -7220,7 +7238,13 @@ static List getAllProperties(IModel model) SpatialCMultiPoint = multiPoint, SpatialCMultiPolygon = multiPolygon, SpatialCPoint = point1, - SpatialCPolygon = polygon1 + SpatialCPolygon = polygon1, + Int32Collection = new[] { 1, 2, 3, 4 }, + DoubleCollection = new[] { 1.2, 3.4 }, + StringCollection = new[] { "AB", "CD" }, + DateTimeCollection = new[] { new DateTime(2023, 9, 7), new DateTime(2023, 11, 14) }, + BoolCollection = new[] { true, false }, + BytesCollection = new[] { new byte[] { 1, 2 }, new byte[] { 3, 4 } } }, new { @@ -7288,6 +7312,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + b.Property("BoolCollection") + .HasColumnType("nvarchar(max)"); + b.Property("Boolean") .HasColumnType("bit"); @@ -7297,6 +7324,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Bytes") .HasColumnType("varbinary(max)"); + b.Property("BytesCollection") + .HasColumnType("nvarchar(max)"); + b.Property("Character") .IsRequired() .HasColumnType("nvarchar(1)"); @@ -7304,6 +7334,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("DateTime") .HasColumnType("datetime2"); + b.Property("DateTimeCollection") + .HasColumnType("nvarchar(max)"); + b.Property("DateTimeOffset") .HasColumnType("datetimeoffset"); @@ -7313,6 +7346,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Double") .HasColumnType("float"); + b.Property("DoubleCollection") + .HasColumnType("nvarchar(max)"); + b.Property("Enum16") .HasColumnType("smallint"); @@ -7343,6 +7379,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Int32") .HasColumnType("int"); + b.Property("Int32Collection") + .HasColumnType("nvarchar(max)"); + b.Property("Int64") .HasColumnType("bigint"); @@ -7400,6 +7439,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("String") .HasColumnType("nvarchar(max)"); + b.Property("StringCollection") + .HasColumnType("nvarchar(max)"); + b.Property("TimeSpan") .HasColumnType("time"); @@ -7420,14 +7462,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) new { Id = 42, + BoolCollection = "[true,false]", Boolean = true, Byte = (byte)55, Bytes = new byte[] { 44, 45 }, + BytesCollection = "[\"AQI=\",\"AwQ=\"]", Character = "9", DateTime = new DateTime(1973, 9, 3, 12, 10, 42, 344, DateTimeKind.Utc), + DateTimeCollection = "[\"2023-09-07T00:00:00\",\"2023-11-14T00:00:00\"]", DateTimeOffset = new DateTimeOffset(new DateTime(1973, 9, 3, 12, 10, 42, 344, DateTimeKind.Unspecified), new TimeSpan(0, 1, 0, 0, 0)), Decimal = 50.0m, Double = 49.0, + DoubleCollection = "[1.2,3.4]", Enum16 = (short)1, Enum32 = 1, Enum64 = 1L, @@ -7438,6 +7484,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) EnumU64 = 1234567890123456789m, Int16 = (short)46, Int32 = 47, + Int32Collection = "[1,2,3,4]", Int64 = 48L, SignedByte = (short)60, Single = 54f, @@ -7456,6 +7503,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) SpatialCPoint = (NetTopologySuite.Geometries.Point)new NetTopologySuite.IO.WKTReader().Read("SRID=4326;POINT Z(1.1 2.2 3.3)"), SpatialCPolygon = (NetTopologySuite.Geometries.Polygon)new NetTopologySuite.IO.WKTReader().Read("SRID=4326;POLYGON ((1.1 2.2, 2.2 2.2, 2.2 1.1, 1.1 2.2))"), String = "FortyThree", + StringCollection = "[\"AB\",\"CD\"]", TimeSpan = new TimeSpan(2, 3, 52, 53, 0), UnsignedInt16 = 56, UnsignedInt32 = 57L, @@ -7583,6 +7631,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) Assert.Equal(4326, ((Geometry)seed["SpatialCMultiPolygon"]).SRID); Assert.Equal(4326, ((Geometry)seed["SpatialCPoint"]).SRID); Assert.Equal(4326, ((Geometry)seed["SpatialCPolygon"]).SRID); + + Assert.Equal("[1,2,3,4]", seed["Int32Collection"]); + Assert.Equal("[1.2,3.4]", seed["DoubleCollection"]); + Assert.Equal("[\"AB\",\"CD\"]", seed["StringCollection"]); + Assert.Equal("[\"2023-09-07T00:00:00\",\"2023-11-14T00:00:00\"]", seed["DateTimeCollection"]); + Assert.Equal("[true,false]", seed["BoolCollection"]); + Assert.Equal("[\"AQI=\",\"AwQ=\"]", seed["BytesCollection"]); }, seed => { From 806c3a210addf55f0bfc95d990a87b13bc085df0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Sep 2023 16:19:41 -0700 Subject: [PATCH 2/4] Bump Microsoft.AspNetCore.OData from 8.2.1 to 8.2.2 (#31628) Bumps [Microsoft.AspNetCore.OData](https://github.com/OData/AspNetCoreOData) from 8.2.1 to 8.2.2. - [Release notes](https://github.com/OData/AspNetCoreOData/releases) - [Commits](https://github.com/OData/AspNetCoreOData/compare/8.2.1...8.2.2) --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.OData dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../EFCore.OData.FunctionalTests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/EFCore.OData.FunctionalTests/EFCore.OData.FunctionalTests.csproj b/test/EFCore.OData.FunctionalTests/EFCore.OData.FunctionalTests.csproj index aa0243a6805..aa9c7fcd207 100644 --- a/test/EFCore.OData.FunctionalTests/EFCore.OData.FunctionalTests.csproj +++ b/test/EFCore.OData.FunctionalTests/EFCore.OData.FunctionalTests.csproj @@ -41,7 +41,7 @@ - + From 6a673261dc13ada23401bb6f4e39672f4c7ea0b0 Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Sat, 9 Sep 2023 10:59:05 +0100 Subject: [PATCH 3/4] Set the key comparer as well as the normal comparer when mapping a primitive collection (#31661) --- .../Storage/Internal/CosmosTypeMapping.cs | 3 +- .../Storage/Internal/InMemoryTypeMapping.cs | 3 +- .../Query/SqlExpressions/SelectExpression.cs | 8 ++---- .../Storage/RelationalTypeMapping.cs | 7 +++-- .../Storage/RelationalTypeMappingSource.cs | 13 +++++---- src/EFCore/Storage/CoreTypeMapping.cs | 6 +++- src/EFCore/Storage/TypeMappingSource.cs | 28 +++++++++++-------- .../JsonTypesCustomMappingSqlServerTest.cs | 12 ++++---- .../Query/JsonQuerySqlServerTest.cs | 6 ++-- .../Internal/ChangeDetectorTest.cs | 4 ++- 10 files changed, 55 insertions(+), 35 deletions(-) diff --git a/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMapping.cs b/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMapping.cs index cb62bd9a9e5..821ebe33886 100644 --- a/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMapping.cs +++ b/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMapping.cs @@ -63,9 +63,10 @@ protected CosmosTypeMapping(CoreTypeMappingParameters parameters) public override CoreTypeMapping Clone( ValueConverter? converter, ValueComparer? comparer = null, + ValueComparer? keyComparer = null, CoreTypeMapping? elementMapping = null, JsonValueReaderWriter? jsonValueReaderWriter = null) - => new CosmosTypeMapping(Parameters.WithComposedConverter(converter, comparer, elementMapping, jsonValueReaderWriter)); + => new CosmosTypeMapping(Parameters.WithComposedConverter(converter, comparer, keyComparer, elementMapping, jsonValueReaderWriter)); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore.InMemory/Storage/Internal/InMemoryTypeMapping.cs b/src/EFCore.InMemory/Storage/Internal/InMemoryTypeMapping.cs index bfd8126ac82..e29aa4b0fa0 100644 --- a/src/EFCore.InMemory/Storage/Internal/InMemoryTypeMapping.cs +++ b/src/EFCore.InMemory/Storage/Internal/InMemoryTypeMapping.cs @@ -56,9 +56,10 @@ private InMemoryTypeMapping(CoreTypeMappingParameters parameters) public override CoreTypeMapping Clone( ValueConverter? converter, ValueComparer? comparer = null, + ValueComparer? keyComparer = null, CoreTypeMapping? elementMapping = null, JsonValueReaderWriter? jsonValueReaderWriter = null) - => new InMemoryTypeMapping(Parameters.WithComposedConverter(converter, comparer, elementMapping, jsonValueReaderWriter)); + => new InMemoryTypeMapping(Parameters.WithComposedConverter(converter, comparer, keyComparer, elementMapping, jsonValueReaderWriter)); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index 9ff0b64c9e8..0ad1dfc7ec8 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -808,8 +808,7 @@ when entityType.IsMappedToJson(): // (OPENJSON, json_each, etc), but we can't use it for distinct, as it would warp the results. // Instead, we will treat every non-key property as identifier. - // TODO: hack/workaround, see #31398 - foreach (var property in entityType.GetDeclaredProperties().Where(p => !p.IsPrimaryKey() && p.GetRelationalTypeMapping().ElementTypeMapping == null)) + foreach (var property in entityType.GetDeclaredProperties().Where(p => !p.IsPrimaryKey())) { typeProjectionIdentifiers.Add(entityProjection.BindProperty(property)); typeProjectionValueComparers.Add(property.GetKeyValueComparer()); @@ -826,8 +825,7 @@ when entityType.IsMappedToJson(): // entity type would have wiped the identifiers when generating the join. Check.DebugAssert(primaryKey != null, "primary key is null."); - // TODO: hack/workaround, see #31398 - foreach (var property in primaryKey.Properties.Where(x => x.GetRelationalTypeMapping().ElementTypeMapping == null)) + foreach (var property in primaryKey.Properties) { typeProjectionIdentifiers.Add(entityProjection.BindProperty(property)); typeProjectionValueComparers.Add(property.GetKeyValueComparer()); @@ -1851,7 +1849,7 @@ ConstantExpression AddStructuralTypeProjection(StructuralTypeProjectionExpressio { ownerEntity = ownership.PrincipalEntityType; } - } + } while (ownerEntity.IsMappedToJson()); var keyPropertyCount = ownerEntity.FindPrimaryKey()!.Properties.Count; diff --git a/src/EFCore.Relational/Storage/RelationalTypeMapping.cs b/src/EFCore.Relational/Storage/RelationalTypeMapping.cs index 1f12134f7b3..8d79b96d2cc 100644 --- a/src/EFCore.Relational/Storage/RelationalTypeMapping.cs +++ b/src/EFCore.Relational/Storage/RelationalTypeMapping.cs @@ -231,16 +231,18 @@ public RelationalTypeMappingParameters WithScale(int? scale) /// /// The converter. /// The comparer. + /// The key comparer. /// The element mapping, or for non-collection mappings. /// The JSON reader/writer, or to leave unchanged. /// The new parameter object. public RelationalTypeMappingParameters WithComposedConverter( ValueConverter? converter, ValueComparer? comparer, + ValueComparer? keyComparer, CoreTypeMapping? elementMapping, JsonValueReaderWriter? jsonValueReaderWriter) => new( - CoreParameters.WithComposedConverter(converter, comparer, elementMapping, jsonValueReaderWriter), + CoreParameters.WithComposedConverter(converter, comparer, keyComparer, elementMapping, jsonValueReaderWriter), StoreType, StoreTypePostfix, DbType, @@ -431,9 +433,10 @@ public virtual RelationalTypeMapping Clone(int? precision, int? scale) public override CoreTypeMapping Clone( ValueConverter? converter, ValueComparer? comparer = null, + ValueComparer? keyComparer = null, CoreTypeMapping? elementMapping = null, JsonValueReaderWriter? jsonValueReaderWriter = null) - => Clone(Parameters.WithComposedConverter(converter, comparer, elementMapping, jsonValueReaderWriter)); + => Clone(Parameters.WithComposedConverter(converter, comparer, keyComparer, elementMapping, jsonValueReaderWriter)); /// /// Clones the type mapping to update facets from the mapping info, if needed. diff --git a/src/EFCore.Relational/Storage/RelationalTypeMappingSource.cs b/src/EFCore.Relational/Storage/RelationalTypeMappingSource.cs index cc5cb6fe9f1..c49945a32de 100644 --- a/src/EFCore.Relational/Storage/RelationalTypeMappingSource.cs +++ b/src/EFCore.Relational/Storage/RelationalTypeMappingSource.cs @@ -231,6 +231,12 @@ protected override CoreTypeMapping FindMapping(in TypeMappingInfo mappingInfo) { var elementType = modelType.TryGetElementType(typeof(IEnumerable<>))!; + var comparer = (ValueComparer?)Activator.CreateInstance( + elementType.IsNullableValueType() + ? typeof(NullableValueTypeListComparer<>).MakeGenericType(elementType.UnwrapNullableType()) + : typeof(ListComparer<>).MakeGenericType(elementMapping!.Comparer.Type), + elementMapping!.Comparer); + return (RelationalTypeMapping)FindMapping( info.WithConverter( // Note that the converter info is only used temporarily here and never creates an instance. @@ -238,11 +244,8 @@ protected override CoreTypeMapping FindMapping(in TypeMappingInfo mappingInfo) .Clone( (ValueConverter)Activator.CreateInstance( typeof(CollectionToJsonStringConverter<>).MakeGenericType(elementType), collectionReaderWriter!)!, - (ValueComparer?)Activator.CreateInstance( - elementType.IsNullableValueType() - ? typeof(NullableValueTypeListComparer<>).MakeGenericType(elementType.UnwrapNullableType()) - : typeof(ListComparer<>).MakeGenericType(elementMapping!.Comparer.Type), - elementMapping!.Comparer), + comparer, + comparer, elementMapping, collectionReaderWriter); } diff --git a/src/EFCore/Storage/CoreTypeMapping.cs b/src/EFCore/Storage/CoreTypeMapping.cs index f84fa623bab..cf4a0030871 100644 --- a/src/EFCore/Storage/CoreTypeMapping.cs +++ b/src/EFCore/Storage/CoreTypeMapping.cs @@ -111,12 +111,14 @@ public CoreTypeMappingParameters( /// /// The converter. /// The comparer. + /// The key comparer. /// The element mapping, or for non-collection mappings. /// The JSON reader/writer, or to leave unchanged. /// The new parameter object. public CoreTypeMappingParameters WithComposedConverter( ValueConverter? converter, ValueComparer? comparer, + ValueComparer? keyComparer, CoreTypeMapping? elementMapping, JsonValueReaderWriter? jsonValueReaderWriter) { @@ -126,7 +128,7 @@ public CoreTypeMappingParameters WithComposedConverter( ClrType, converter ?? Converter, comparer ?? Comparer, - KeyComparer, + keyComparer?? KeyComparer, ProviderValueComparer, ValueGeneratorFactory, elementMapping ?? ElementTypeMapping, @@ -266,12 +268,14 @@ public virtual ValueComparer ProviderValueComparer /// /// The converter to use. /// The comparer to use, or for to keep the default. + /// The comparer to use when the value is a key, or for to keep the default. /// The element mapping, or for non-collection mappings. /// The JSON reader/writer, or to leave unchanged. /// A new type mapping public abstract CoreTypeMapping Clone( ValueConverter? converter, ValueComparer? comparer = null, + ValueComparer? keyComparer = null, CoreTypeMapping? elementMapping = null, JsonValueReaderWriter? jsonValueReaderWriter = null); diff --git a/src/EFCore/Storage/TypeMappingSource.cs b/src/EFCore/Storage/TypeMappingSource.cs index 855ba977af8..4edbd91de83 100644 --- a/src/EFCore/Storage/TypeMappingSource.cs +++ b/src/EFCore/Storage/TypeMappingSource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Concurrent; +using ValueComparer = Microsoft.EntityFrameworkCore.ChangeTracking.ValueComparer; namespace Microsoft.EntityFrameworkCore.Storage; @@ -182,25 +183,30 @@ protected TypeMappingSource(TypeMappingSourceDependencies dependencies) Type? providerType, CoreTypeMapping? elementMapping) { - var elementType = modelType.TryGetElementType(typeof(IEnumerable<>))!; + if (TryFindJsonCollectionMapping( + info, modelType, providerType, ref elementMapping, out var collectionReaderWriter)) + { + var elementType = modelType.TryGetElementType(typeof(IEnumerable<>))!; + var comparer = (ValueComparer?)Activator.CreateInstance( + elementType.IsNullableValueType() + ? typeof(NullableValueTypeListComparer<>).MakeGenericType(elementType.UnwrapNullableType()) + : typeof(ListComparer<>).MakeGenericType(elementMapping!.Comparer.Type), + elementMapping!.Comparer); - return TryFindJsonCollectionMapping( - info, modelType, providerType, ref elementMapping, out var collectionReaderWriter) - ? FindMapping( + return FindMapping( info.WithConverter( // Note that the converter info is only used temporarily here and never creates an instance. new ValueConverterInfo(modelType, typeof(string), _ => null!)))! .Clone( (ValueConverter)Activator.CreateInstance( typeof(CollectionToJsonStringConverter<>).MakeGenericType(elementType), collectionReaderWriter!)!, - (ValueComparer?)Activator.CreateInstance( - elementType.IsNullableValueType() - ? typeof(NullableValueTypeListComparer<>).MakeGenericType(elementType.UnwrapNullableType()) - : typeof(ListComparer<>).MakeGenericType(elementMapping!.Comparer.Type), - elementMapping!.Comparer), + comparer, + comparer, elementMapping, - collectionReaderWriter) - : null; + collectionReaderWriter); + } + + return null; } /// diff --git a/test/EFCore.SqlServer.FunctionalTests/JsonTypesCustomMappingSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/JsonTypesCustomMappingSqlServerTest.cs index 4992c1549d7..6cee8193491 100644 --- a/test/EFCore.SqlServer.FunctionalTests/JsonTypesCustomMappingSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/JsonTypesCustomMappingSqlServerTest.cs @@ -55,6 +55,11 @@ private class TestSqlServerTypeMappingSource( info.CoreTypeMappingInfo, modelType, providerType, ref elementMapping, out var collectionReaderWriter)) { var elementType = TryGetElementType(modelType, typeof(IEnumerable<>))!; + var comparer = (ValueComparer?)Activator.CreateInstance( + IsNullableValueType(elementType) + ? typeof(NullableValueTypeListComparer<>).MakeGenericType(UnwrapNullableType(elementType)) + : typeof(ListComparer<>).MakeGenericType(elementMapping!.Comparer.Type), + elementMapping!.Comparer); return (RelationalTypeMapping)FindMapping( info.WithConverter( @@ -63,11 +68,8 @@ private class TestSqlServerTypeMappingSource( .Clone( (ValueConverter)Activator.CreateInstance( typeof(CollectionToJsonStringConverter<>).MakeGenericType(elementType), collectionReaderWriter!)!, - (ValueComparer?)Activator.CreateInstance( - IsNullableValueType(elementType) - ? typeof(NullableValueTypeListComparer<>).MakeGenericType(UnwrapNullableType(elementType)) - : typeof(ListComparer<>).MakeGenericType(elementMapping!.Comparer.Type), - elementMapping!.Comparer), + comparer, + comparer, elementMapping, collectionReaderWriter); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/JsonQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/JsonQuerySqlServerTest.cs index d15c70ada14..788944b8645 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/JsonQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/JsonQuerySqlServerTest.cs @@ -1338,7 +1338,7 @@ [OwnedCollectionBranch] nvarchar(max) '$.OwnedCollectionBranch' AS JSON, [OwnedReferenceBranch] nvarchar(max) '$.OwnedReferenceBranch' AS JSON ) AS [o] ) AS [t] -ORDER BY [j].[Id], [t].[Name] +ORDER BY [j].[Id], [t].[Name], [t].[Names], [t].[Number] """); } @@ -1400,7 +1400,7 @@ WHERE CAST(JSON_VALUE([o2].[value], '$.Date') AS datetime2) <> '2000-01-01T00:00 ) AS [t2] ) AS [t1] LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId] -ORDER BY [j].[Id], [t].[c], [t].[key], [t0].[Name], [t0].[Number], [t1].[c1], [t1].[key], [t1].[c10], [t1].[key0] +ORDER BY [j].[Id], [t].[c], [t].[key], [t0].[Name], [t0].[Names], [t0].[Number], [t0].[Numbers], [t1].[c1], [t1].[key], [t1].[c10], [t1].[key0] """); } @@ -1426,7 +1426,7 @@ [OwnedReferenceLeaf] nvarchar(max) '$.OwnedReferenceLeaf' AS JSON ) AS [o] ) AS [t] LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId] -ORDER BY [j].[Id], [t].[Date], [t].[Enum], [t].[Fraction], [t].[NullableEnum] +ORDER BY [j].[Id], [t].[Date], [t].[Enum], [t].[Enums], [t].[Fraction], [t].[NullableEnum], [t].[NullableEnums] """); } diff --git a/test/EFCore.Tests/ChangeTracking/Internal/ChangeDetectorTest.cs b/test/EFCore.Tests/ChangeTracking/Internal/ChangeDetectorTest.cs index 7b9c501aee6..747fb8a21ec 100644 --- a/test/EFCore.Tests/ChangeTracking/Internal/ChangeDetectorTest.cs +++ b/test/EFCore.Tests/ChangeTracking/Internal/ChangeDetectorTest.cs @@ -314,9 +314,11 @@ public ConcreteTypeMapping(Type clrType, ValueConverter converter, ValueComparer public override CoreTypeMapping Clone( ValueConverter converter, ValueComparer comparer = null, + ValueComparer keyComparer = null, CoreTypeMapping elementMapping = null, JsonValueReaderWriter jsonValueReaderWriter = null) - => new ConcreteTypeMapping(Parameters.WithComposedConverter(converter, comparer, elementMapping, jsonValueReaderWriter)); + => new ConcreteTypeMapping(Parameters.WithComposedConverter( + converter, comparer, keyComparer, elementMapping, jsonValueReaderWriter)); protected override CoreTypeMapping Clone(CoreTypeMappingParameters parameters) => new ConcreteTypeMapping(parameters); From ecfc1ced12714a972f538a071d23cdf34aafbb2e Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Sun, 10 Sep 2023 13:36:08 +0100 Subject: [PATCH 4/4] API review updates (#31673) --- .../CosmosSqlTranslatingExpressionVisitor.cs | 8 +- .../Storage/Internal/CosmosTypeMapping.cs | 2 +- ...yExpressionTranslatingExpressionVisitor.cs | 8 +- .../Storage/Internal/InMemoryTypeMapping.cs | 2 +- .../Internal/PropertyChangedInterceptor.cs | 2 +- .../Internal/PropertyChangingInterceptor.cs | 2 +- ...lationalSqlTranslatingExpressionVisitor.cs | 14 +- .../Storage/Internal/NullTypeMapping.cs | 2 +- .../Storage/RelationalTypeMapping.cs | 37 +- .../Storage/RelationalTypeMappingSource.cs | 8 +- .../RelationalConverterMappingHints.cs | 2 +- .../Internal/SqlServerTypeMappingSource.cs | 2 +- ...ypePrimitiveCollectionBuilderExtensions.cs | 49 -- ...itePrimitiveCollectionBuilderExtensions.cs | 46 -- .../Internal/SqliteTypeMappingSource.cs | 2 +- .../Internal/ArrayPropertyValues.cs | 2 +- .../Internal/EntryPropertyValues.cs | 2 +- .../ChangeTracking/Internal/IInternalEntry.cs | 638 +++++++++--------- .../InternalEntityEntry.OriginalValues.cs | 10 +- .../Internal/InternalEntityEntry.cs | 60 +- .../Internal/OriginalValuesFactoryFactory.cs | 2 +- .../Internal/SidecarValuesFactoryFactory.cs | 2 +- ...leFullyNullableDependentKeyValueFactory.cs | 6 +- ...mpleNonNullableDependentKeyValueFactory.cs | 6 +- .../SimpleNullableDependentKeyValueFactory.cs | 6 +- ...llablePrincipalDependentKeyValueFactory.cs | 6 +- .../Internal/SnapshotFactoryFactory.cs | 4 +- src/EFCore/Diagnostics/ILoggingOptions.cs | 4 +- .../Diagnostics/Internal/LoggingOptions.cs | 6 +- .../Builders/IConventionPropertyBuilder.cs | 2 +- .../Builders/PrimitiveCollectionBuilder.cs | 2 +- .../PropertyDiscoveryConvention.cs | 2 +- src/EFCore/Metadata/IClrPropertyGetter.cs | 12 +- src/EFCore/Metadata/IConventionProperty.cs | 14 +- src/EFCore/Metadata/IMutableProperty.cs | 12 +- src/EFCore/Metadata/INavigationBase.cs | 2 +- src/EFCore/Metadata/IProperty.cs | 6 + src/EFCore/Metadata/IReadOnlyProperty.cs | 2 +- .../Metadata/Internal/ClrPropertyGetter.cs | 12 +- src/EFCore/Metadata/Internal/EntityType.cs | 8 +- .../Metadata/Internal/IRuntimeEntityType.cs | 4 +- .../Internal/InternalPropertyBuilder.cs | 10 +- .../Internal/InternalTypeBaseBuilder.cs | 2 +- src/EFCore/Metadata/Internal/Property.cs | 56 +- .../Internal/PropertyAccessorsFactory.cs | 14 +- src/EFCore/Metadata/ParameterBindingInfo.cs | 2 +- src/EFCore/Metadata/RuntimeEntityType.cs | 12 +- src/EFCore/Metadata/RuntimeProperty.cs | 4 + src/EFCore/Storage/CoreTypeMapping.cs | 2 +- .../Json/JsonWarningEnumReaderWriter.cs | 2 +- src/EFCore/Storage/TypeMappingSource.cs | 8 +- .../ValueConversion/ConverterMappingHints.cs | 4 +- src/EFCore/Update/UpdateEntryExtensions.cs | 68 +- .../Storage/RelationalCommandTest.cs | 2 +- .../Storage/RelationalTypeMappingTest.cs | 12 +- .../TestRelationalTypeMappingSource.cs | 2 +- .../EverythingIsBytesSqlServerTest.cs | 2 +- .../EverythingIsStringsSqlServerTest.cs | 2 +- .../JsonTypesCustomMappingSqlServerTest.cs | 2 +- .../SpatialQuerySqlServerGeographyFixture.cs | 4 +- .../SpatialQuerySqlServerGeometryFixture.cs | 2 +- .../Storage/SqlServerTypeMappingTest.cs | 4 +- .../Query/SpatialQuerySqliteFixture.cs | 4 +- .../SqliteApiConsistencyTest.cs | 3 - .../Internal/ChangeDetectorTest.cs | 2 +- .../Conventions/ConventionDispatcherTest.cs | 16 +- .../Internal/ClrPropertyGetterFactoryTest.cs | 27 +- .../Internal/ClrPropertySetterFactoryTest.cs | 3 + 68 files changed, 583 insertions(+), 706 deletions(-) delete mode 100644 src/EFCore.Sqlite.Core/Extensions/SqliteComplexTypePrimitiveCollectionBuilderExtensions.cs delete mode 100644 src/EFCore.Sqlite.Core/Extensions/SqlitePrimitiveCollectionBuilderExtensions.cs diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs index 7079cec7b45..f34e5b1c1cb 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs @@ -840,7 +840,7 @@ private bool TryRewriteContainsEntity(Expression source, Expression item, out Ex var propertyGetter = property.GetGetter(); foreach (var value in values) { - propertyValueList.Add(propertyGetter.GetStructuralTypeClrValue(value)); + propertyValueList.Add(propertyGetter.GetClrValue(value)); } rewrittenSource = Expression.Constant(propertyValueList); @@ -971,7 +971,7 @@ private Expression CreatePropertyAccessExpression(Expression target, IProperty p { case SqlConstantExpression sqlConstantExpression: return Expression.Constant( - property.GetGetter().GetStructuralTypeClrValue(sqlConstantExpression.Value!), property.ClrType.MakeNullable()); + property.GetGetter().GetClrValue(sqlConstantExpression.Value!), property.ClrType.MakeNullable()); case SqlParameterExpression sqlParameterExpression when sqlParameterExpression.Name.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal): @@ -1002,7 +1002,7 @@ when memberInitExpression.Bindings.SingleOrDefault( private static T ParameterValueExtractor(QueryContext context, string baseParameterName, IProperty property) { var baseParameter = context.ParameterValues[baseParameterName]; - return baseParameter == null ? (T)(object)null : (T)property.GetGetter().GetStructuralTypeClrValue(baseParameter); + return baseParameter == null ? (T)(object)null : (T)property.GetGetter().GetClrValue(baseParameter); } private static List ParameterListValueExtractor( @@ -1016,7 +1016,7 @@ private static List ParameterListValueExtractor( } var getter = property.GetGetter(); - return baseListParameter.Select(e => e != null ? (TProperty)getter.GetStructuralTypeClrValue(e) : (TProperty)(object)null).ToList(); + return baseListParameter.Select(e => e != null ? (TProperty)getter.GetClrValue(e) : (TProperty)(object)null).ToList(); } private static bool IsNullSqlConstantExpression(Expression expression) diff --git a/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMapping.cs b/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMapping.cs index 821ebe33886..726e907c271 100644 --- a/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMapping.cs +++ b/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMapping.cs @@ -60,7 +60,7 @@ protected CosmosTypeMapping(CoreTypeMappingParameters parameters) /// 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 override CoreTypeMapping Clone( + public override CoreTypeMapping WithComposedConverter( ValueConverter? converter, ValueComparer? comparer = null, ValueComparer? keyComparer = null, diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs index b6c4f0131db..f649b462a92 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs @@ -1288,7 +1288,7 @@ private bool TryRewriteContainsEntity(Expression? source, Expression item, [NotN var propertyGetter = property.GetGetter(); foreach (var value in values) { - propertyValueList.Add(propertyGetter.GetStructuralTypeClrValue(value)); + propertyValueList.Add(propertyGetter.GetClrValue(value)); } rewrittenSource = Expression.Constant(propertyValueList); @@ -1436,7 +1436,7 @@ private Expression CreatePropertyAccessExpression(Expression target, IProperty p return Expression.Constant( constantExpression.Value is null ? null - : property.GetGetter().GetStructuralTypeClrValue(constantExpression.Value), + : property.GetGetter().GetClrValue(constantExpression.Value), property.ClrType.MakeNullable()); case MethodCallExpression { Method.IsGenericMethod: true } methodCallExpression @@ -1479,7 +1479,7 @@ when CanEvaluate(memberInitExpression): private static T? ParameterValueExtractor(QueryContext context, string baseParameterName, IProperty property) { var baseParameter = context.ParameterValues[baseParameterName]; - return baseParameter == null ? (T?)(object?)null : (T?)property.GetGetter().GetStructuralTypeClrValue(baseParameter); + return baseParameter == null ? (T?)(object?)null : (T?)property.GetGetter().GetClrValue(baseParameter); } private static List? ParameterListValueExtractor( @@ -1493,7 +1493,7 @@ when CanEvaluate(memberInitExpression): } var getter = property.GetGetter(); - return baseListParameter.Select(e => e != null ? (TProperty?)getter.GetStructuralTypeClrValue(e) : (TProperty?)(object?)null).ToList(); + return baseListParameter.Select(e => e != null ? (TProperty?)getter.GetClrValue(e) : (TProperty?)(object?)null).ToList(); } private static ConstantExpression GetValue(Expression expression) diff --git a/src/EFCore.InMemory/Storage/Internal/InMemoryTypeMapping.cs b/src/EFCore.InMemory/Storage/Internal/InMemoryTypeMapping.cs index e29aa4b0fa0..34bd3b51288 100644 --- a/src/EFCore.InMemory/Storage/Internal/InMemoryTypeMapping.cs +++ b/src/EFCore.InMemory/Storage/Internal/InMemoryTypeMapping.cs @@ -53,7 +53,7 @@ private InMemoryTypeMapping(CoreTypeMappingParameters parameters) /// 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 override CoreTypeMapping Clone( + public override CoreTypeMapping WithComposedConverter( ValueConverter? converter, ValueComparer? comparer = null, ValueComparer? keyComparer = null, diff --git a/src/EFCore.Proxies/Proxies/Internal/PropertyChangedInterceptor.cs b/src/EFCore.Proxies/Proxies/Internal/PropertyChangedInterceptor.cs index f67e5fc52a0..2637f9e07c8 100644 --- a/src/EFCore.Proxies/Proxies/Internal/PropertyChangedInterceptor.cs +++ b/src/EFCore.Proxies/Proxies/Internal/PropertyChangedInterceptor.cs @@ -94,7 +94,7 @@ private void HandleChanged(IInvocation invocation, IPropertyBase property, IEqua if (_checkEquality) { - var oldValue = property.GetGetter().GetClrValue(invocation.Proxy); + var oldValue = property.GetGetter().GetClrValueUsingContainingEntity(invocation.Proxy); invocation.Proceed(); diff --git a/src/EFCore.Proxies/Proxies/Internal/PropertyChangingInterceptor.cs b/src/EFCore.Proxies/Proxies/Internal/PropertyChangingInterceptor.cs index 670639d5369..ed1cfe38e51 100644 --- a/src/EFCore.Proxies/Proxies/Internal/PropertyChangingInterceptor.cs +++ b/src/EFCore.Proxies/Proxies/Internal/PropertyChangingInterceptor.cs @@ -92,7 +92,7 @@ private void HandleChanging(IInvocation invocation, IPropertyBase property, IEqu { if (_checkEquality) { - var oldValue = property.GetGetter().GetClrValue(invocation.Proxy); + var oldValue = property.GetGetter().GetClrValueUsingContainingEntity(invocation.Proxy); var newValue = invocation.Arguments[^1]; if (!(comparer?.Equals(oldValue, newValue) ?? Equals(oldValue, newValue))) diff --git a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs index 46309019c68..3a96b93fb13 100644 --- a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs @@ -1684,7 +1684,7 @@ private bool TryRewriteContainsEntity(Expression source, Expression item, [NotNu var propertyGetter = property.GetGetter(); foreach (var value in values) { - propertyValueList.Add(propertyGetter.GetStructuralTypeClrValue(value)); + propertyValueList.Add(propertyGetter.GetClrValue(value)); } rewrittenSource = Expression.Constant(propertyValueList); @@ -1974,14 +1974,14 @@ private Expression CreatePropertyAccessExpression(Expression target, IProperty p return Expression.Constant( sqlConstantExpression.Value is null ? null - : property.GetGetter().GetStructuralTypeClrValue(sqlConstantExpression.Value), + : property.GetGetter().GetClrValue(sqlConstantExpression.Value), property.ClrType.MakeNullable()); case ConstantExpression sqlConstantExpression: return Expression.Constant( sqlConstantExpression.Value is null ? null - : property.GetGetter().GetStructuralTypeClrValue(sqlConstantExpression.Value), + : property.GetGetter().GetClrValue(sqlConstantExpression.Value), property.ClrType.MakeNullable()); case SqlParameterExpression sqlParameterExpression @@ -2035,7 +2035,7 @@ private Expression CreateComplexPropertyAccessExpression(Expression target, ICom => target switch { SqlConstantExpression constant => Expression.Constant( - constant.Value is null ? null : complexProperty.GetGetter().GetStructuralTypeClrValue(constant.Value), + constant.Value is null ? null : complexProperty.GetGetter().GetClrValue(constant.Value), complexProperty.ClrType.MakeNullable()), SqlParameterExpression sqlParameterExpression @@ -2070,11 +2070,11 @@ when memberInitExpression.Bindings.SingleOrDefault(mb => mb.Member.Name == compl break; } - baseValue = complexProperty.GetGetter().GetStructuralTypeClrValue(baseValue); + baseValue = complexProperty.GetGetter().GetClrValue(baseValue); } } - return baseValue == null ? (T?)(object?)null : (T?)property.GetGetter().GetStructuralTypeClrValue(baseValue); + return baseValue == null ? (T?)(object?)null : (T?)property.GetGetter().GetClrValue(baseValue); } private static List? ParameterListValueExtractor( @@ -2088,7 +2088,7 @@ when memberInitExpression.Bindings.SingleOrDefault(mb => mb.Member.Name == compl } var getter = property.GetGetter(); - return baseListParameter.Select(e => e != null ? (TProperty?)getter.GetStructuralTypeClrValue(e) : (TProperty?)(object?)null).ToList(); + return baseListParameter.Select(e => e != null ? (TProperty?)getter.GetClrValue(e) : (TProperty?)(object?)null).ToList(); } private sealed class ParameterBasedComplexPropertyChainExpression : Expression diff --git a/src/EFCore.Relational/Storage/Internal/NullTypeMapping.cs b/src/EFCore.Relational/Storage/Internal/NullTypeMapping.cs index 366d62c80ed..19e4aa9aeb3 100644 --- a/src/EFCore.Relational/Storage/Internal/NullTypeMapping.cs +++ b/src/EFCore.Relational/Storage/Internal/NullTypeMapping.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Storage.Json; -namespace Microsoft.EntityFrameworkCore.Storage; +namespace Microsoft.EntityFrameworkCore.Storage.Internal; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore.Relational/Storage/RelationalTypeMapping.cs b/src/EFCore.Relational/Storage/RelationalTypeMapping.cs index 8d79b96d2cc..e6588e4e1d9 100644 --- a/src/EFCore.Relational/Storage/RelationalTypeMapping.cs +++ b/src/EFCore.Relational/Storage/RelationalTypeMapping.cs @@ -4,6 +4,7 @@ using System.Collections.Concurrent; using System.Data; using System.Globalization; +using Microsoft.EntityFrameworkCore.Storage.Internal; using Microsoft.EntityFrameworkCore.Storage.Json; namespace Microsoft.EntityFrameworkCore.Storage; @@ -278,7 +279,7 @@ private static MethodInfo GetDataReaderMethod(string name) /// /// Gets the mapping to be used when the only piece of information is that there is a null value. /// - public static readonly NullTypeMapping NullMapping = NullTypeMapping.Default; + public static readonly RelationalTypeMapping NullMapping = NullTypeMapping.Default; /// /// Initializes a new instance of the class. @@ -417,7 +418,7 @@ protected override CoreTypeMapping Clone(CoreTypeMappingParameters parameters) /// The name of the database type. /// The size of data the property is configured to store, or null if no size is configured. /// The newly created mapping. - public virtual RelationalTypeMapping Clone(string storeType, int? size) + public virtual RelationalTypeMapping WithStoreTypeAndSize(string storeType, int? size) => Clone(Parameters.WithStoreTypeAndSize(storeType, size)); /// @@ -426,11 +427,11 @@ public virtual RelationalTypeMapping Clone(string storeType, int? size) /// The precision of data the property is configured to store, or null if no size is configured. /// The scale of data the property is configured to store, or null if no size is configured. /// The newly created mapping. - public virtual RelationalTypeMapping Clone(int? precision, int? scale) + public virtual RelationalTypeMapping WithPrecisionAndScale(int? precision, int? scale) => Clone(Parameters.WithPrecisionAndScale(precision, scale)); /// - public override CoreTypeMapping Clone( + public override CoreTypeMapping WithComposedConverter( ValueConverter? converter, ValueComparer? comparer = null, ValueComparer? keyComparer = null, @@ -443,36 +444,10 @@ public override CoreTypeMapping Clone( /// /// The mapping info containing the facets to use. /// The cloned mapping, or the original mapping if no clone was needed. - public virtual RelationalTypeMapping Clone( + public virtual RelationalTypeMapping WithTypeMappingInfo( in RelationalTypeMappingInfo mappingInfo) => Clone(Parameters.WithTypeMappingInfo(mappingInfo)); - /// - public override CoreTypeMapping Clone( - in TypeMappingInfo? mappingInfo = null, - Type? clrType = null, - ValueConverter? converter = null, - ValueComparer? comparer = null, - ValueComparer? keyComparer = null, - ValueComparer? providerValueComparer = null, - CoreTypeMapping? elementMapping = null, - JsonValueReaderWriter? jsonValueReaderWriter = null) - => Clone( - mappingInfo == null - ? null - : new RelationalTypeMappingInfo( - unicode: mappingInfo.Value.IsUnicode, - size: mappingInfo.Value.Size, - precision: mappingInfo.Value.Precision, - scale: mappingInfo.Value.Scale), - clrType, - converter, - comparer, - keyComparer, - providerValueComparer, - elementMapping, - jsonValueReaderWriter); - /// /// Clones the type mapping to update any parameter if needed. /// diff --git a/src/EFCore.Relational/Storage/RelationalTypeMappingSource.cs b/src/EFCore.Relational/Storage/RelationalTypeMappingSource.cs index c49945a32de..c7876503837 100644 --- a/src/EFCore.Relational/Storage/RelationalTypeMappingSource.cs +++ b/src/EFCore.Relational/Storage/RelationalTypeMappingSource.cs @@ -174,7 +174,7 @@ protected override CoreTypeMapping FindMapping(in TypeMappingInfo mappingInfo) if (mapping != null) { - mapping = (RelationalTypeMapping)mapping.Clone( + mapping = (RelationalTypeMapping)mapping.WithComposedConverter( secondConverterInfo.Create(), jsonValueReaderWriter: mappingInfoUsed.JsonValueReaderWriter); break; @@ -184,7 +184,7 @@ protected override CoreTypeMapping FindMapping(in TypeMappingInfo mappingInfo) if (mapping != null) { - mapping = (RelationalTypeMapping)mapping.Clone( + mapping = (RelationalTypeMapping)mapping.WithComposedConverter( converterInfo.Create(), jsonValueReaderWriter: mappingInfo.JsonValueReaderWriter); break; @@ -203,7 +203,7 @@ protected override CoreTypeMapping FindMapping(in TypeMappingInfo mappingInfo) if (mapping != null && customConverter != null) { - mapping = (RelationalTypeMapping)mapping.Clone( + mapping = (RelationalTypeMapping)mapping.WithComposedConverter( customConverter, jsonValueReaderWriter: mappingInfo.JsonValueReaderWriter); } @@ -241,7 +241,7 @@ protected override CoreTypeMapping FindMapping(in TypeMappingInfo mappingInfo) info.WithConverter( // Note that the converter info is only used temporarily here and never creates an instance. new ValueConverterInfo(modelType, typeof(string), _ => null!)))! - .Clone( + .WithComposedConverter( (ValueConverter)Activator.CreateInstance( typeof(CollectionToJsonStringConverter<>).MakeGenericType(elementType), collectionReaderWriter!)!, comparer, diff --git a/src/EFCore.Relational/Storage/ValueConversion/RelationalConverterMappingHints.cs b/src/EFCore.Relational/Storage/ValueConversion/RelationalConverterMappingHints.cs index ea677e5b762..24ab3940d2b 100644 --- a/src/EFCore.Relational/Storage/ValueConversion/RelationalConverterMappingHints.cs +++ b/src/EFCore.Relational/Storage/ValueConversion/RelationalConverterMappingHints.cs @@ -77,7 +77,7 @@ public override ConverterMappingHints With(ConverterMappingHints? hints) (hints as RelationalConverterMappingHints)?.DbType ?? DbType); /// - public override ConverterMappingHints Override(ConverterMappingHints? hints) + public override ConverterMappingHints OverrideWith(ConverterMappingHints? hints) => hints == null ? this : new RelationalConverterMappingHints( diff --git a/src/EFCore.SqlServer/Storage/Internal/SqlServerTypeMappingSource.cs b/src/EFCore.SqlServer/Storage/Internal/SqlServerTypeMappingSource.cs index 0a718f8f829..f05557997c9 100644 --- a/src/EFCore.SqlServer/Storage/Internal/SqlServerTypeMappingSource.cs +++ b/src/EFCore.SqlServer/Storage/Internal/SqlServerTypeMappingSource.cs @@ -233,7 +233,7 @@ public SqlServerTypeMappingSource( /// protected override RelationalTypeMapping? FindMapping(in RelationalTypeMappingInfo mappingInfo) => base.FindMapping(mappingInfo) - ?? FindRawMapping(mappingInfo)?.Clone(mappingInfo); + ?? FindRawMapping(mappingInfo)?.WithTypeMappingInfo(mappingInfo); private RelationalTypeMapping? FindRawMapping(RelationalTypeMappingInfo mappingInfo) { diff --git a/src/EFCore.Sqlite.Core/Extensions/SqliteComplexTypePrimitiveCollectionBuilderExtensions.cs b/src/EFCore.Sqlite.Core/Extensions/SqliteComplexTypePrimitiveCollectionBuilderExtensions.cs deleted file mode 100644 index 19fd5c79297..00000000000 --- a/src/EFCore.Sqlite.Core/Extensions/SqliteComplexTypePrimitiveCollectionBuilderExtensions.cs +++ /dev/null @@ -1,49 +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; - -/// -/// SQLite-specific extension methods for . -/// -/// -/// See Modeling entity types and relationships, and -/// Accessing SQLite databases with EF Core for more information and examples. -/// -public static class SqliteComplexTypePrimitiveCollectionBuilderExtensions -{ - /// - /// Configures the SRID of the column that the property maps to when targeting SQLite. - /// - /// - /// See Spatial data, and - /// Accessing SQLite databases with EF Core for more information and examples. - /// - /// The builder for the property being configured. - /// The SRID. - /// The same builder instance so that multiple calls can be chained. - public static ComplexTypePrimitiveCollectionBuilder HasSrid( - this ComplexTypePrimitiveCollectionBuilder primitiveCollectionBuilder, - int srid) - { - primitiveCollectionBuilder.Metadata.SetSrid(srid); - - return primitiveCollectionBuilder; - } - - /// - /// Configures the SRID of the column that the property maps to when targeting SQLite. - /// - /// - /// See Spatial data, and - /// Accessing SQLite databases with EF Core for more information and examples. - /// - /// The builder for the property being configured. - /// The SRID. - /// The same builder instance so that multiple calls can be chained. - public static ComplexTypePrimitiveCollectionBuilder HasSrid( - this ComplexTypePrimitiveCollectionBuilder primitiveCollectionBuilder, - int srid) - => (ComplexTypePrimitiveCollectionBuilder)HasSrid( - (ComplexTypePrimitiveCollectionBuilder)primitiveCollectionBuilder, srid); -} diff --git a/src/EFCore.Sqlite.Core/Extensions/SqlitePrimitiveCollectionBuilderExtensions.cs b/src/EFCore.Sqlite.Core/Extensions/SqlitePrimitiveCollectionBuilderExtensions.cs deleted file mode 100644 index 0a675c038ff..00000000000 --- a/src/EFCore.Sqlite.Core/Extensions/SqlitePrimitiveCollectionBuilderExtensions.cs +++ /dev/null @@ -1,46 +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; - -/// -/// SQLite-specific extension methods for . -/// -/// -/// See Modeling entity types and relationships, and -/// Accessing SQLite databases with EF Core for more information and examples. -/// -public static class SqlitePrimitiveCollectionBuilderExtensions -{ - /// - /// Configures the SRID of the column that the property maps to when targeting SQLite. - /// - /// - /// See Spatial data, and - /// Accessing SQLite databases with EF Core for more information and examples. - /// - /// The builder for the property being configured. - /// The SRID. - /// The same builder instance so that multiple calls can be chained. - public static PrimitiveCollectionBuilder HasSrid(this PrimitiveCollectionBuilder primitiveCollectionBuilder, int srid) - { - primitiveCollectionBuilder.Metadata.SetSrid(srid); - - return primitiveCollectionBuilder; - } - - /// - /// Configures the SRID of the column that the property maps to when targeting SQLite. - /// - /// - /// See Spatial data, and - /// Accessing SQLite databases with EF Core for more information and examples. - /// - /// The builder for the property being configured. - /// The SRID. - /// The same builder instance so that multiple calls can be chained. - public static PrimitiveCollectionBuilder HasSrid( - this PrimitiveCollectionBuilder primitiveCollectionBuilder, - int srid) - => (PrimitiveCollectionBuilder)HasSrid((PrimitiveCollectionBuilder)primitiveCollectionBuilder, srid); -} diff --git a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteTypeMappingSource.cs b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteTypeMappingSource.cs index 23a4aad518f..fce854a835e 100644 --- a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteTypeMappingSource.cs +++ b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteTypeMappingSource.cs @@ -129,7 +129,7 @@ public static bool IsSpatialiteType(string columnType) return mapping != null && mappingInfo.StoreTypeName != null - ? mapping.Clone(mappingInfo.StoreTypeName, null) + ? mapping.WithStoreTypeAndSize(mappingInfo.StoreTypeName, null) : mapping; } diff --git a/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs b/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs index c8c54fcc2d6..9ee9cc38daa 100644 --- a/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs +++ b/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs @@ -56,7 +56,7 @@ public override void SetValues(object obj) { if (!Properties[i].IsShadowProperty()) { - SetValue(i, Properties[i].GetGetter().GetClrValue(obj)); + SetValue(i, Properties[i].GetGetter().GetClrValueUsingContainingEntity(obj)); } } } diff --git a/src/EFCore/ChangeTracking/Internal/EntryPropertyValues.cs b/src/EFCore/ChangeTracking/Internal/EntryPropertyValues.cs index 0ee834c9b62..927f2e1c678 100644 --- a/src/EFCore/ChangeTracking/Internal/EntryPropertyValues.cs +++ b/src/EFCore/ChangeTracking/Internal/EntryPropertyValues.cs @@ -49,7 +49,7 @@ public override void SetValues(object obj) { foreach (var property in Properties.Where(p => !p.IsShadowProperty())) { - SetValueInternal(property, property.GetGetter().GetClrValue(obj)); + SetValueInternal(property, property.GetGetter().GetClrValueUsingContainingEntity(obj)); } } else diff --git a/src/EFCore/ChangeTracking/Internal/IInternalEntry.cs b/src/EFCore/ChangeTracking/Internal/IInternalEntry.cs index bd973bb81df..69944659dc7 100644 --- a/src/EFCore/ChangeTracking/Internal/IInternalEntry.cs +++ b/src/EFCore/ChangeTracking/Internal/IInternalEntry.cs @@ -1,322 +1,322 @@ // 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; - -namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; - -/// -/// 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. -/// -public interface IInternalEntry -{ - /// - /// 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. - /// - object? this[IPropertyBase propertyBase] { get; set; } - - /// - /// 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. - /// - IRuntimeEntityType EntityType { get; } - - /// - /// 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. - /// - bool HasConceptualNull { get; } - - /// - /// 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. - /// - IStateManager StateManager { get; } - - /// - /// 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. - /// - void AcceptChanges(); - - /// - /// 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. - /// - void DiscardStoreGeneratedValues(); - - /// - /// 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. - /// - object? GetCurrentValue(IPropertyBase propertyBase); - - /// - /// 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. - /// - TProperty GetCurrentValue(IPropertyBase propertyBase); - - /// - /// 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. - /// - object? GetOriginalValue(IPropertyBase propertyBase); - - /// - /// 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. - /// - TProperty GetOriginalValue(IProperty property); - - /// - /// 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. - /// - object? GetPreStoreGeneratedCurrentValue(IPropertyBase propertyBase); - - /// - /// 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. - /// - bool HasExplicitValue(IProperty property); - - /// - /// 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. - /// - bool HasTemporaryValue(IProperty property); - - /// - /// 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. - /// - bool IsConceptualNull(IProperty property); - - /// - /// 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. - /// - bool IsModified(IProperty property); - - /// - /// 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. - /// - bool FlaggedAsStoreGenerated(int propertyIndex); - - /// - /// 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. - /// - bool FlaggedAsTemporary(int propertyIndex); - - /// - /// 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. - /// - bool IsStoreGenerated(IProperty property); - - /// - /// 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. - /// - bool IsUnknown(IProperty property); - - /// - /// 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. - /// - void MarkAsTemporary(IProperty property, bool temporary); - - /// - /// 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. - /// - void MarkUnchangedFromQuery(); - - /// - /// 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. - /// - void MarkUnknown(IProperty property); - - /// - /// 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. - /// - IInternalEntry PrepareToSave(); - - /// - /// 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. - /// - public object Object { get; } // This won't work for value types - - /// - /// 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. - /// - public void HandleConceptualNulls(bool sensitiveLoggingEnabled, bool force, bool isCascadeDelete); - - /// - /// 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. - /// - void PropagateValue(InternalEntityEntry principalEntry, IProperty principalProperty, IProperty dependentProperty, bool isMaterialization = false, bool setModified = true); - - /// - /// 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. - /// - T ReadOriginalValue(IProperty property, int originalValueIndex); - - /// - /// 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. - /// - object? ReadPropertyValue(IPropertyBase propertyBase); - - /// - /// 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. - /// - T ReadStoreGeneratedValue(int storeGeneratedIndex); - - /// - /// 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. - /// - T ReadTemporaryValue(int storeGeneratedIndex); - - /// - /// 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. - /// - T ReadShadowValue(int shadowIndex); - - /// - /// 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. - /// - void SetOriginalValue(IPropertyBase propertyBase, object? value, int index = -1); - - /// - /// 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. - /// - void SetProperty(IPropertyBase propertyBase, object? value, bool isMaterialization, bool setModified = true, bool isCascadeDelete = false); - - /// - /// 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. - /// - void SetPropertyModified(IProperty property, bool changeState = true, bool isModified = true, bool isConceptualNull = false, bool acceptChanges = false); - - /// - /// 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. - /// - void SetEntityState( - EntityState entityState, - bool acceptChanges = false, - bool modifyProperties = true); - - /// - /// 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. - /// - void OnComplexPropertyModified(IComplexProperty property, bool isModified = true); - - /// - /// 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. - /// - void SetStoreGeneratedValue(IProperty property, object? value, bool setModified = true); - - /// - /// 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. - /// - void SetTemporaryValue(IProperty property, object? value, bool setModified = true); -} +// using Microsoft.EntityFrameworkCore.Metadata.Internal; +// +// namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; +// +// /// +// /// 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. +// /// +// public interface IInternalEntry +// { +// /// +// /// 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. +// /// +// object? this[IPropertyBase propertyBase] { get; set; } +// +// /// +// /// 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. +// /// +// IRuntimeEntityType EntityType { get; } +// +// /// +// /// 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. +// /// +// bool HasConceptualNull { get; } +// +// /// +// /// 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. +// /// +// IStateManager StateManager { get; } +// +// /// +// /// 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. +// /// +// void AcceptChanges(); +// +// /// +// /// 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. +// /// +// void DiscardStoreGeneratedValues(); +// +// /// +// /// 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. +// /// +// object? GetCurrentValue(IPropertyBase propertyBase); +// +// /// +// /// 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. +// /// +// TProperty GetCurrentValue(IPropertyBase propertyBase); +// +// /// +// /// 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. +// /// +// object? GetOriginalValue(IPropertyBase propertyBase); +// +// /// +// /// 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. +// /// +// TProperty GetOriginalValue(IProperty property); +// +// /// +// /// 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. +// /// +// object? GetPreStoreGeneratedCurrentValue(IPropertyBase propertyBase); +// +// /// +// /// 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. +// /// +// bool HasExplicitValue(IProperty property); +// +// /// +// /// 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. +// /// +// bool HasTemporaryValue(IProperty property); +// +// /// +// /// 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. +// /// +// bool IsConceptualNull(IProperty property); +// +// /// +// /// 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. +// /// +// bool IsModified(IProperty property); +// +// /// +// /// 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. +// /// +// bool FlaggedAsStoreGenerated(int propertyIndex); +// +// /// +// /// 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. +// /// +// bool FlaggedAsTemporary(int propertyIndex); +// +// /// +// /// 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. +// /// +// bool IsStoreGenerated(IProperty property); +// +// /// +// /// 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. +// /// +// bool IsUnknown(IProperty property); +// +// /// +// /// 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. +// /// +// void MarkAsTemporary(IProperty property, bool temporary); +// +// /// +// /// 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. +// /// +// void MarkUnchangedFromQuery(); +// +// /// +// /// 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. +// /// +// void MarkUnknown(IProperty property); +// +// /// +// /// 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. +// /// +// IInternalEntry PrepareToSave(); +// +// /// +// /// 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. +// /// +// public object Object { get; } // This won't work for value types +// +// /// +// /// 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. +// /// +// public void HandleConceptualNulls(bool sensitiveLoggingEnabled, bool force, bool isCascadeDelete); +// +// /// +// /// 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. +// /// +// void PropagateValue(InternalEntityEntry principalEntry, IProperty principalProperty, IProperty dependentProperty, bool isMaterialization = false, bool setModified = true); +// +// /// +// /// 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. +// /// +// T ReadOriginalValue(IProperty property, int originalValueIndex); +// +// /// +// /// 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. +// /// +// object? ReadPropertyValue(IPropertyBase propertyBase); +// +// /// +// /// 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. +// /// +// T ReadStoreGeneratedValue(int storeGeneratedIndex); +// +// /// +// /// 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. +// /// +// T ReadTemporaryValue(int storeGeneratedIndex); +// +// /// +// /// 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. +// /// +// T ReadShadowValue(int shadowIndex); +// +// /// +// /// 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. +// /// +// void SetOriginalValue(IPropertyBase propertyBase, object? value, int index = -1); +// +// /// +// /// 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. +// /// +// void SetProperty(IPropertyBase propertyBase, object? value, bool isMaterialization, bool setModified = true, bool isCascadeDelete = false); +// +// /// +// /// 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. +// /// +// void SetPropertyModified(IProperty property, bool changeState = true, bool isModified = true, bool isConceptualNull = false, bool acceptChanges = false); +// +// /// +// /// 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. +// /// +// void SetEntityState( +// EntityState entityState, +// bool acceptChanges = false, +// bool modifyProperties = true); +// +// /// +// /// 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. +// /// +// void OnComplexPropertyModified(IComplexProperty property, bool isModified = true); +// +// /// +// /// 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. +// /// +// void SetStoreGeneratedValue(IProperty property, object? value, bool setModified = true); +// +// /// +// /// 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. +// /// +// void SetTemporaryValue(IProperty property, object? value, bool setModified = true); +// } diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.OriginalValues.cs b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.OriginalValues.cs index fd3b1581ea5..6e7b552b3fc 100644 --- a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.OriginalValues.cs +++ b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.OriginalValues.cs @@ -11,12 +11,12 @@ private readonly struct OriginalValues { private readonly ISnapshot _values; - public OriginalValues(IInternalEntry entry) + public OriginalValues(InternalEntityEntry entry) { _values = entry.EntityType.OriginalValuesFactory(entry); } - public object? GetValue(IInternalEntry entry, IProperty property) + public object? GetValue(InternalEntityEntry entry, IProperty property) { var index = property.GetOriginalValueIndex(); if (index == -1) @@ -28,7 +28,7 @@ public OriginalValues(IInternalEntry entry) return IsEmpty ? entry[property] : _values[index]; } - public T GetValue(IInternalEntry entry, IProperty property, int index) + public T GetValue(InternalEntityEntry entry, IProperty property, int index) { if (index == -1) { @@ -65,7 +65,7 @@ public void SetValue(IProperty property, object? value, int index) _values[index] = SnapshotValue(property, value); } - public void RejectChanges(IInternalEntry entry) + public void RejectChanges(InternalEntityEntry entry) { if (IsEmpty) { @@ -82,7 +82,7 @@ public void RejectChanges(IInternalEntry entry) } } - public void AcceptChanges(IInternalEntry entry) + public void AcceptChanges(InternalEntityEntry entry) { if (IsEmpty) { diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs index 78f982f9ed9..8daa35ecbb2 100644 --- a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs +++ b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs @@ -16,7 +16,7 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// 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 sealed partial class InternalEntityEntry : IUpdateEntry, IInternalEntry +public sealed partial class InternalEntityEntry : IUpdateEntry { private readonly StateData _stateData; private OriginalValues _originalValues; @@ -420,7 +420,7 @@ private void HandleSharedIdentityEntry(EntityState newState) throw new InvalidOperationException( CoreStrings.IdentityConflictSensitive( EntityType.DisplayName(), - BuildCurrentValuesString(EntityType.FindPrimaryKey()!.Properties))); + this.BuildCurrentValuesString(EntityType.FindPrimaryKey()!.Properties))); } throw new InvalidOperationException( @@ -793,7 +793,7 @@ public void MarkAsTemporary(IProperty property, bool temporary) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public static readonly MethodInfo FlaggedAsTemporaryMethod - = typeof(IInternalEntry).GetMethod(nameof(IInternalEntry.FlaggedAsTemporary))!; + = typeof(InternalEntityEntry).GetMethod(nameof(InternalEntityEntry.FlaggedAsTemporary))!; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -802,7 +802,7 @@ public static readonly MethodInfo FlaggedAsTemporaryMethod /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public static readonly MethodInfo FlaggedAsStoreGeneratedMethod - = typeof(IInternalEntry).GetMethod(nameof(IInternalEntry.FlaggedAsStoreGenerated))!; + = typeof(InternalEntityEntry).GetMethod(nameof(InternalEntityEntry.FlaggedAsStoreGenerated))!; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -837,7 +837,7 @@ public void MarkUnknown(IProperty property) => _stateData.FlagProperty(property.GetIndex(), PropertyFlag.Unknown, true); internal static MethodInfo MakeReadShadowValueMethod(Type type) - => typeof(IInternalEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadShadowValue))! + => typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadShadowValue))! .MakeGenericMethod(type); /// @@ -850,7 +850,7 @@ public T ReadShadowValue(int shadowIndex) => _shadowValues.GetValue(shadowIndex); private static readonly MethodInfo ReadOriginalValueMethod - = typeof(IInternalEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadOriginalValue))!; + = typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadOriginalValue))!; [UnconditionalSuppressMessage( "ReflectionAnalysis", "IL2060", @@ -892,7 +892,7 @@ internal static MethodInfo MakeReadStoreGeneratedValueMethod(Type type) => ReadStoreGeneratedValueMethod.MakeGenericMethod(type); private static readonly MethodInfo ReadStoreGeneratedValueMethod - = typeof(IInternalEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadStoreGeneratedValue))!; + = typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadStoreGeneratedValue))!; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -904,7 +904,7 @@ public T ReadStoreGeneratedValue(int storeGeneratedIndex) => _storeGeneratedValues.GetValue(storeGeneratedIndex); private static readonly MethodInfo ReadTemporaryValueMethod - = typeof(IInternalEntry).GetMethod(nameof(ReadTemporaryValue))!; + = typeof(InternalEntityEntry).GetMethod(nameof(ReadTemporaryValue))!; [UnconditionalSuppressMessage( "ReflectionAnalysis", "IL2060", @@ -922,7 +922,7 @@ public T ReadTemporaryValue(int storeGeneratedIndex) => _temporaryValues.GetValue(storeGeneratedIndex); private static readonly MethodInfo GetCurrentValueMethod - = typeof(IInternalEntry).GetTypeInfo().GetDeclaredMethods(nameof(GetCurrentValue)).Single( + = typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethods(nameof(GetCurrentValue)).Single( m => m.IsGenericMethod); [UnconditionalSuppressMessage( @@ -938,7 +938,7 @@ internal static MethodInfo MakeGetCurrentValueMethod(Type type) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public TProperty GetCurrentValue(IPropertyBase propertyBase) - => ((Func)propertyBase.GetPropertyAccessors().CurrentValueGetter)(this); + => ((Func)propertyBase.GetPropertyAccessors().CurrentValueGetter)(this); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -947,7 +947,7 @@ public TProperty GetCurrentValue(IPropertyBase propertyBase) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public TProperty GetOriginalValue(IProperty property) - => ((Func)property.GetPropertyAccessors().OriginalValueGetter!)(this); + => ((Func)property.GetPropertyAccessors().OriginalValueGetter!)(this); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -968,7 +968,7 @@ public TProperty GetRelationshipSnapshotValue(IPropertyBase propertyB public object? ReadPropertyValue(IPropertyBase propertyBase) => propertyBase.IsShadowProperty() ? _shadowValues[propertyBase.GetShadowIndex()] - : propertyBase.GetGetter().GetClrValue(Entity); + : propertyBase.GetGetter().GetClrValueUsingContainingEntity(Entity); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -1717,7 +1717,7 @@ public void HandleConceptualNulls(bool sensitiveLoggingEnabled, bool force, bool CoreStrings.RelationshipConceptualNullSensitive( foreignKey.PrincipalEntityType.DisplayName(), EntityType.DisplayName(), - BuildOriginalValuesString(foreignKey.Properties))); + this.BuildOriginalValuesString(foreignKey.Properties))); } throw new InvalidOperationException( @@ -1740,7 +1740,7 @@ public void HandleConceptualNulls(bool sensitiveLoggingEnabled, bool force, bool CoreStrings.PropertyConceptualNullSensitive( property.Name, EntityType.DisplayName(), - BuildOriginalValuesString(new[] { property }))); + this.BuildOriginalValuesString(new[] { property }))); } throw new InvalidOperationException( @@ -1798,7 +1798,7 @@ public bool HasExplicitValue(IProperty property) private bool HasSentinel(IProperty property) => property.IsShadowProperty() ? AreEqual(_shadowValues[property.GetShadowIndex()], property.Sentinel, property) - : property.GetGetter().HasSentinel(Entity); + : property.GetGetter().HasSentinelUsingContainingEntity(Entity); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -2046,24 +2046,6 @@ public bool IsLoaded(INavigationBase navigation) return lazyLoaderProperty != null ? (ILazyLoader?)this[lazyLoaderProperty] : null; } - /// - /// 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. - /// - public string BuildCurrentValuesString(IEnumerable properties) - => ((IInternalEntry)this).BuildCurrentValuesString(properties); - - /// - /// 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. - /// - public string BuildOriginalValuesString(IEnumerable properties) - => ((IInternalEntry)this).BuildOriginalValuesString(properties); - /// /// 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 @@ -2090,18 +2072,6 @@ public DebugView DebugView IEntityType IUpdateEntry.EntityType => EntityType; - IRuntimeEntityType IInternalEntry.EntityType - => EntityType; - - object IInternalEntry.Object - => Entity; - - IInternalEntry IInternalEntry.PrepareToSave() - => PrepareToSave(); - - void IInternalEntry.SetEntityState(EntityState entityState, bool acceptChanges, bool modifyProperties) - => SetEntityState(entityState, acceptChanges, modifyProperties); - private enum CurrentValueType { Normal, diff --git a/src/EFCore/ChangeTracking/Internal/OriginalValuesFactoryFactory.cs b/src/EFCore/ChangeTracking/Internal/OriginalValuesFactoryFactory.cs index ebc0663ccdc..cb38d9f6878 100644 --- a/src/EFCore/ChangeTracking/Internal/OriginalValuesFactoryFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/OriginalValuesFactoryFactory.cs @@ -11,7 +11,7 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// 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 class OriginalValuesFactoryFactory : SnapshotFactoryFactory +public class OriginalValuesFactoryFactory : SnapshotFactoryFactory { /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/ChangeTracking/Internal/SidecarValuesFactoryFactory.cs b/src/EFCore/ChangeTracking/Internal/SidecarValuesFactoryFactory.cs index e0f758c815e..c66736bdad9 100644 --- a/src/EFCore/ChangeTracking/Internal/SidecarValuesFactoryFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/SidecarValuesFactoryFactory.cs @@ -11,7 +11,7 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal; /// 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 class SidecarValuesFactoryFactory : SnapshotFactoryFactory +public class SidecarValuesFactoryFactory : SnapshotFactoryFactory { /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/ChangeTracking/Internal/SimpleFullyNullableDependentKeyValueFactory.cs b/src/EFCore/ChangeTracking/Internal/SimpleFullyNullableDependentKeyValueFactory.cs index 3f4334aa65b..7ac738c4966 100644 --- a/src/EFCore/ChangeTracking/Internal/SimpleFullyNullableDependentKeyValueFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/SimpleFullyNullableDependentKeyValueFactory.cs @@ -61,7 +61,7 @@ public virtual bool TryCreateFromBuffer(in ValueBuffer valueBuffer, [NotNullWhen /// public override bool TryCreateFromCurrentValues(IUpdateEntry entry, [NotNullWhen(true)] out TKey? key) { - key = ((Func)_propertyAccessors.CurrentValueGetter)((IInternalEntry)entry); + key = ((Func)_propertyAccessors.CurrentValueGetter)((InternalEntityEntry)entry); return key != null; } @@ -73,7 +73,7 @@ public override bool TryCreateFromCurrentValues(IUpdateEntry entry, [NotNullWhen /// public virtual bool TryCreateFromPreStoreGeneratedCurrentValues(IUpdateEntry entry, [NotNullWhen(true)] out TKey? key) { - key = ((Func)_propertyAccessors.PreStoreGeneratedCurrentValueGetter)((IInternalEntry)entry); + key = ((Func)_propertyAccessors.PreStoreGeneratedCurrentValueGetter)((InternalEntityEntry)entry); return key != null; } @@ -85,7 +85,7 @@ public virtual bool TryCreateFromPreStoreGeneratedCurrentValues(IUpdateEntry ent /// public override bool TryCreateFromOriginalValues(IUpdateEntry entry, [NotNullWhen(true)] out TKey? key) { - key = ((Func)_propertyAccessors.OriginalValueGetter!)((IInternalEntry)entry); + key = ((Func)_propertyAccessors.OriginalValueGetter!)((InternalEntityEntry)entry); return key != null; } diff --git a/src/EFCore/ChangeTracking/Internal/SimpleNonNullableDependentKeyValueFactory.cs b/src/EFCore/ChangeTracking/Internal/SimpleNonNullableDependentKeyValueFactory.cs index c41962e0e35..2c9162b6ab5 100644 --- a/src/EFCore/ChangeTracking/Internal/SimpleNonNullableDependentKeyValueFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/SimpleNonNullableDependentKeyValueFactory.cs @@ -68,7 +68,7 @@ public virtual bool TryCreateFromBuffer(in ValueBuffer valueBuffer, [NotNullWhen /// public override bool TryCreateFromCurrentValues(IUpdateEntry entry, [NotNullWhen(true)] out TKey? key) { - key = ((Func)_propertyAccessors.CurrentValueGetter)((IInternalEntry)entry)!; + key = ((Func)_propertyAccessors.CurrentValueGetter)((InternalEntityEntry)entry)!; return true; } @@ -80,7 +80,7 @@ public override bool TryCreateFromCurrentValues(IUpdateEntry entry, [NotNullWhen /// public virtual bool TryCreateFromPreStoreGeneratedCurrentValues(IUpdateEntry entry, [NotNullWhen(true)] out TKey? key) { - key = ((Func)_propertyAccessors.PreStoreGeneratedCurrentValueGetter)((IInternalEntry)entry)!; + key = ((Func)_propertyAccessors.PreStoreGeneratedCurrentValueGetter)((InternalEntityEntry)entry)!; return true; } @@ -92,7 +92,7 @@ public virtual bool TryCreateFromPreStoreGeneratedCurrentValues(IUpdateEntry ent /// public override bool TryCreateFromOriginalValues(IUpdateEntry entry, [NotNullWhen(true)] out TKey? key) { - key = ((Func)_propertyAccessors.OriginalValueGetter!)((IInternalEntry)entry)!; + key = ((Func)_propertyAccessors.OriginalValueGetter!)((InternalEntityEntry)entry)!; return true; } diff --git a/src/EFCore/ChangeTracking/Internal/SimpleNullableDependentKeyValueFactory.cs b/src/EFCore/ChangeTracking/Internal/SimpleNullableDependentKeyValueFactory.cs index 85b357c0e13..ce52fb1cd8d 100644 --- a/src/EFCore/ChangeTracking/Internal/SimpleNullableDependentKeyValueFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/SimpleNullableDependentKeyValueFactory.cs @@ -66,7 +66,7 @@ public virtual bool TryCreateFromBuffer(in ValueBuffer valueBuffer, out TKey key /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public override bool TryCreateFromCurrentValues(IUpdateEntry entry, out TKey key) - => HandleNullableValue(((Func)_propertyAccessors.CurrentValueGetter)((IInternalEntry)entry), out key); + => HandleNullableValue(((Func)_propertyAccessors.CurrentValueGetter)((InternalEntityEntry)entry), out key); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -76,7 +76,7 @@ public override bool TryCreateFromCurrentValues(IUpdateEntry entry, out TKey key /// public virtual bool TryCreateFromPreStoreGeneratedCurrentValues(IUpdateEntry entry, out TKey key) => HandleNullableValue( - ((Func)_propertyAccessors.PreStoreGeneratedCurrentValueGetter)((IInternalEntry)entry), out key); + ((Func)_propertyAccessors.PreStoreGeneratedCurrentValueGetter)((InternalEntityEntry)entry), out key); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -85,7 +85,7 @@ public virtual bool TryCreateFromPreStoreGeneratedCurrentValues(IUpdateEntry ent /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public override bool TryCreateFromOriginalValues(IUpdateEntry entry, out TKey key) - => HandleNullableValue(((Func)_propertyAccessors.OriginalValueGetter!)((InternalEntityEntry)entry), out key); + => HandleNullableValue(((Func)_propertyAccessors.OriginalValueGetter!)((InternalEntityEntry)entry), out key); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/ChangeTracking/Internal/SimpleNullablePrincipalDependentKeyValueFactory.cs b/src/EFCore/ChangeTracking/Internal/SimpleNullablePrincipalDependentKeyValueFactory.cs index a32ed396555..b350bec9434 100644 --- a/src/EFCore/ChangeTracking/Internal/SimpleNullablePrincipalDependentKeyValueFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/SimpleNullablePrincipalDependentKeyValueFactory.cs @@ -72,7 +72,7 @@ public virtual bool TryCreateFromBuffer(in ValueBuffer valueBuffer, [NotNullWhen /// public override bool TryCreateFromCurrentValues(IUpdateEntry entry, [NotNullWhen(true)] out TKey? key) { - key = (TKey)(object)((Func)_propertyAccessors.CurrentValueGetter)((IInternalEntry)entry)!; + key = (TKey)(object)((Func)_propertyAccessors.CurrentValueGetter)((InternalEntityEntry)entry)!; return true; } @@ -84,7 +84,7 @@ public override bool TryCreateFromCurrentValues(IUpdateEntry entry, [NotNullWhen /// public virtual bool TryCreateFromPreStoreGeneratedCurrentValues(IUpdateEntry entry, [NotNullWhen(true)] out TKey? key) { - key = (TKey)(object)((Func)_propertyAccessors.PreStoreGeneratedCurrentValueGetter)((IInternalEntry)entry)!; + key = (TKey)(object)((Func)_propertyAccessors.PreStoreGeneratedCurrentValueGetter)((InternalEntityEntry)entry)!; return true; } @@ -96,7 +96,7 @@ public virtual bool TryCreateFromPreStoreGeneratedCurrentValues(IUpdateEntry ent /// public override bool TryCreateFromOriginalValues(IUpdateEntry entry, [NotNullWhen(true)] out TKey? key) { - key = (TKey)(object)((Func)_propertyAccessors.OriginalValueGetter!)((IInternalEntry)entry)!; + key = (TKey)(object)((Func)_propertyAccessors.OriginalValueGetter!)((InternalEntityEntry)entry)!; return true; } diff --git a/src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs b/src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs index 8ac652f44a1..aba7539759d 100644 --- a/src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs @@ -171,9 +171,7 @@ protected virtual Expression CreateSnapshotExpression( Expression.Assign( entityVariable, Expression.Convert( - Expression.Property(parameter!, parameter!.Type == typeof(InternalEntityEntry) - ? nameof(InternalEntityEntry.Entity) - : nameof(IInternalEntry.Object)), + Expression.Property(parameter!, nameof(InternalEntityEntry.Entity)), entityType!)), constructorExpression }) diff --git a/src/EFCore/Diagnostics/ILoggingOptions.cs b/src/EFCore/Diagnostics/ILoggingOptions.cs index 77dd28e0795..3060c484713 100644 --- a/src/EFCore/Diagnostics/ILoggingOptions.cs +++ b/src/EFCore/Diagnostics/ILoggingOptions.cs @@ -43,7 +43,7 @@ public interface ILoggingOptions : ISingletonOptions /// /// Returns if a warning about string values for the given enum type has not yet been performed. /// - /// The type to check. + /// The type to check. /// Whether or not a warning has been issued. - bool ShouldWarnForEnumType(Type type); + bool ShouldWarnForStringEnumValueInJson(Type enumType); } diff --git a/src/EFCore/Diagnostics/Internal/LoggingOptions.cs b/src/EFCore/Diagnostics/Internal/LoggingOptions.cs index 98b67bd7a9c..1ce5f190765 100644 --- a/src/EFCore/Diagnostics/Internal/LoggingOptions.cs +++ b/src/EFCore/Diagnostics/Internal/LoggingOptions.cs @@ -104,14 +104,14 @@ public virtual void Validate(IDbContextOptions options) public virtual WarningsConfiguration WarningsConfiguration { get; private set; } = null!; /// - public virtual bool ShouldWarnForEnumType(Type type) + public virtual bool ShouldWarnForStringEnumValueInJson(Type enumType) { - if (_warnedForStringEnums.ContainsKey(type)) + if (_warnedForStringEnums.ContainsKey(enumType)) { return false; } - _warnedForStringEnums[type] = true; + _warnedForStringEnums[enumType] = true; return true; } } diff --git a/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs b/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs index f1a68be7ef6..cc8e81b2a92 100644 --- a/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs +++ b/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs @@ -545,7 +545,7 @@ bool CanSetProviderValueComparer( /// 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. /// - IConventionElementTypeBuilder? ElementType(bool elementType, bool fromDataAnnotation = false); + IConventionElementTypeBuilder? SetElementType(bool elementType, bool fromDataAnnotation = false); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder.cs b/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder.cs index 82d8e475714..7e2152b87ae 100644 --- a/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder.cs +++ b/src/EFCore/Metadata/Builders/PrimitiveCollectionBuilder.cs @@ -365,7 +365,7 @@ public virtual PrimitiveCollectionBuilder HasField(string fieldName) /// /// A builder to configure the collection element type. public virtual ElementTypeBuilder ElementType() - => new((IMutableElementType)Builder.Metadata.GetElementType()!); + => new(Builder.Metadata.GetElementType()!); /// /// Configures the elements of this collection. diff --git a/src/EFCore/Metadata/Conventions/PropertyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/PropertyDiscoveryConvention.cs index 8cfb7acfd50..311a5d6fdfe 100644 --- a/src/EFCore/Metadata/Conventions/PropertyDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/PropertyDiscoveryConvention.cs @@ -94,7 +94,7 @@ private void Process(IConventionEntityTypeBuilder entityTypeBuilder) var propertyBuilder = entityTypeBuilder.Property(propertyInfo); if (mapping?.ElementTypeMapping != null) { - propertyBuilder?.ElementType(true); + propertyBuilder?.SetElementType(true); } } } diff --git a/src/EFCore/Metadata/IClrPropertyGetter.cs b/src/EFCore/Metadata/IClrPropertyGetter.cs index 5121716081a..2b6a2838ee2 100644 --- a/src/EFCore/Metadata/IClrPropertyGetter.cs +++ b/src/EFCore/Metadata/IClrPropertyGetter.cs @@ -24,26 +24,26 @@ public interface IClrPropertyGetter /// /// The entity instance. /// The property value. - object? GetClrValue(object entity); + object? GetClrValueUsingContainingEntity(object entity); /// /// Checks whether or not the property is set to the CLR default for its type. /// /// The entity instance. /// if the property value is the CLR default; it is any other value. - bool HasSentinel(object entity); + bool HasSentinelUsingContainingEntity(object entity); /// /// Gets the property value from the declaring type. /// - /// The complex type instance instance. + /// The entity or complex type instance. /// The property value. - object? GetStructuralTypeClrValue(object complexObject); + object? GetClrValue(object structuralObject); /// /// Checks whether or not the property is set to the CLR default for its type. /// - /// The complex type instance instance. + /// The entity or complex type instance. /// if the property value is the CLR default; it is any other value. - bool HasStructuralTypeSentinelValue(object complexObject); + bool HasSentinel(object structuralObject); } diff --git a/src/EFCore/Metadata/IConventionProperty.cs b/src/EFCore/Metadata/IConventionProperty.cs index 4bc664c3527..86384ce8566 100644 --- a/src/EFCore/Metadata/IConventionProperty.cs +++ b/src/EFCore/Metadata/IConventionProperty.cs @@ -460,17 +460,27 @@ bool IsImplicitlyCreated() /// The configuration source for . ConfigurationSource? GetJsonValueReaderWriterTypeConfigurationSource(); + /// + /// Gets the configuration for elements of the primitive collection represented by this property. + /// + /// The configuration for the elements. + new IConventionElementType? GetElementType(); + /// /// Sets the configuration for elements of the primitive collection represented by this property. /// - /// If , then this is a collection of primitive elements. + /// If , then the type mapping has an element type, otherwise it is removed. /// Indicates whether the configuration was specified using a data annotation. /// The configuration for the elements. - IElementType? ElementType(bool primitiveCollection, bool fromDataAnnotation = false); + IConventionElementType? SetElementType(bool elementType, bool fromDataAnnotation = false); /// /// Returns the configuration source for . /// /// The configuration source for . ConfigurationSource? GetElementTypeConfigurationSource(); + + /// + IReadOnlyElementType? IReadOnlyProperty.GetElementType() + => GetElementType(); } diff --git a/src/EFCore/Metadata/IMutableProperty.cs b/src/EFCore/Metadata/IMutableProperty.cs index 5b9ea2539c8..39f3b203e3c 100644 --- a/src/EFCore/Metadata/IMutableProperty.cs +++ b/src/EFCore/Metadata/IMutableProperty.cs @@ -273,11 +273,17 @@ void SetProviderValueComparer( /// void SetJsonValueReaderWriterType(Type? readerWriterType); + /// + /// Gets the configuration for elements of the primitive collection represented by this property. + /// + /// The configuration for the elements. + new IMutableElementType? GetElementType(); + /// /// Sets the configuration for elements of the primitive collection represented by this property. /// /// If , then this is a collection of primitive elements. - void ElementType(bool elementType); + void SetElementType(bool elementType); /// bool IReadOnlyProperty.IsNullable @@ -290,4 +296,8 @@ ValueGenerated IReadOnlyProperty.ValueGenerated /// bool IReadOnlyProperty.IsConcurrencyToken => IsConcurrencyToken; + + /// + IReadOnlyElementType? IReadOnlyProperty.GetElementType() + => GetElementType(); } diff --git a/src/EFCore/Metadata/INavigationBase.cs b/src/EFCore/Metadata/INavigationBase.cs index 27664c247ef..2eec136e42b 100644 --- a/src/EFCore/Metadata/INavigationBase.cs +++ b/src/EFCore/Metadata/INavigationBase.cs @@ -62,7 +62,7 @@ void SetIsLoadedWhenNoTracking(object entity) foreach (var serviceProperty in serviceProperties) { - ((ILazyLoader?)serviceProperty.GetGetter().GetClrValue(entity))?.SetLoaded(entity, Name); + ((ILazyLoader?)serviceProperty.GetGetter().GetClrValueUsingContainingEntity(entity))?.SetLoaded(entity, Name); } } } diff --git a/src/EFCore/Metadata/IProperty.cs b/src/EFCore/Metadata/IProperty.cs index cbf7f7c3429..82eb39d9283 100644 --- a/src/EFCore/Metadata/IProperty.cs +++ b/src/EFCore/Metadata/IProperty.cs @@ -100,6 +100,12 @@ IEqualityComparer CreateKeyEqualityComparer() /// The comparer. new ValueComparer GetProviderValueComparer(); + /// + /// Gets the configuration for elements of the primitive collection represented by this property. + /// + /// The configuration for the elements. + new IElementType? GetElementType(); + internal const DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes = System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors diff --git a/src/EFCore/Metadata/IReadOnlyProperty.cs b/src/EFCore/Metadata/IReadOnlyProperty.cs index 708ea5f2e46..182f0cccbe0 100644 --- a/src/EFCore/Metadata/IReadOnlyProperty.cs +++ b/src/EFCore/Metadata/IReadOnlyProperty.cs @@ -177,7 +177,7 @@ CoreTypeMapping GetTypeMapping() /// Gets the configuration for elements of the primitive collection represented by this property. /// /// The configuration for the elements. - IElementType? GetElementType(); + IReadOnlyElementType? GetElementType(); /// /// Finds the first principal property that the given property is constrained by diff --git a/src/EFCore/Metadata/Internal/ClrPropertyGetter.cs b/src/EFCore/Metadata/Internal/ClrPropertyGetter.cs index a7f74c546ae..19018008d92 100644 --- a/src/EFCore/Metadata/Internal/ClrPropertyGetter.cs +++ b/src/EFCore/Metadata/Internal/ClrPropertyGetter.cs @@ -45,7 +45,7 @@ public ClrPropertyGetter( /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public object? GetClrValue(object entity) + public object? GetClrValueUsingContainingEntity(object entity) => _getter((TEntity)entity); /// @@ -55,7 +55,7 @@ public ClrPropertyGetter( /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasSentinel(object entity) + public bool HasSentinelUsingContainingEntity(object entity) => _hasSentinelValue((TEntity)entity); /// @@ -65,8 +65,8 @@ public bool HasSentinel(object entity) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public object? GetStructuralTypeClrValue(object complexObject) - => _structuralTypeGetter((TStructuralType)complexObject); + public object? GetClrValue(object structuralObject) + => _structuralTypeGetter((TStructuralType)structuralObject); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -75,6 +75,6 @@ public bool HasSentinel(object entity) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasStructuralTypeSentinelValue(object complexObject) - => _hasStructuralTypeSentinelValue((TStructuralType)complexObject); + public bool HasSentinel(object structuralObject) + => _hasStructuralTypeSentinelValue((TStructuralType)structuralObject); } diff --git a/src/EFCore/Metadata/Internal/EntityType.cs b/src/EFCore/Metadata/Internal/EntityType.cs index e9b012c5066..83807c1bea7 100644 --- a/src/EFCore/Metadata/Internal/EntityType.cs +++ b/src/EFCore/Metadata/Internal/EntityType.cs @@ -61,8 +61,8 @@ private readonly SortedDictionary _triggers private InstantiationBinding? _serviceOnlyConstructorBinding; private Func? _relationshipSnapshotFactory; - private Func? _originalValuesFactory; - private Func? _temporaryValuesFactory; + private Func? _originalValuesFactory; + private Func? _temporaryValuesFactory; private Func? _storeGeneratedValuesFactory; private Func? _shadowValuesFactory; private Func? _emptyShadowValuesFactory; @@ -2285,7 +2285,7 @@ public virtual Func RelationshipSnapshotFactory /// 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 Func OriginalValuesFactory + public virtual Func OriginalValuesFactory => NonCapturingLazyInitializer.EnsureInitialized( ref _originalValuesFactory, this, static entityType => @@ -2315,7 +2315,7 @@ public virtual Func StoreGeneratedValuesFactory /// 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 Func TemporaryValuesFactory + public virtual Func TemporaryValuesFactory => NonCapturingLazyInitializer.EnsureInitialized( ref _temporaryValuesFactory, this, static entityType => diff --git a/src/EFCore/Metadata/Internal/IRuntimeEntityType.cs b/src/EFCore/Metadata/Internal/IRuntimeEntityType.cs index cd2c5449b96..30c960c2dfe 100644 --- a/src/EFCore/Metadata/Internal/IRuntimeEntityType.cs +++ b/src/EFCore/Metadata/Internal/IRuntimeEntityType.cs @@ -105,7 +105,7 @@ int ComplexPropertyCount /// 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. /// - Func OriginalValuesFactory { get; } + Func OriginalValuesFactory { get; } /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -121,7 +121,7 @@ int ComplexPropertyCount /// 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. /// - Func TemporaryValuesFactory { get; } + Func TemporaryValuesFactory { get; } /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs b/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs index 9339a4940c6..d20f3be7fec 100644 --- a/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs @@ -564,7 +564,7 @@ public virtual bool CanSetConversion(Type? providerClrType, ConfigurationSource? { if (CanSetConverter(converterType, configurationSource)) { - Metadata.ElementType(false, configurationSource); + Metadata.SetElementType(false, configurationSource); Metadata.SetProviderClrType(null, configurationSource); Metadata.SetValueConverter(converterType, configurationSource); @@ -776,11 +776,11 @@ public virtual bool CanSetProviderValueComparer( /// 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 InternalElementTypeBuilder? ElementType(bool elementType, ConfigurationSource configurationSource) + public virtual InternalElementTypeBuilder? SetElementType(bool elementType, ConfigurationSource configurationSource) { if (CanSetElementType(elementType, configurationSource)) { - Metadata.ElementType(elementType, configurationSource); + Metadata.SetElementType(elementType, configurationSource); Metadata.SetValueConverter((Type?)null, configurationSource); return new InternalElementTypeBuilder((ElementType)Metadata.GetElementType()!, ModelBuilder); } @@ -1523,8 +1523,8 @@ bool IConventionPropertyBuilder.CanSetProviderValueComparer( /// 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. /// - IConventionElementTypeBuilder? IConventionPropertyBuilder.ElementType(bool elementType, bool fromDataAnnotation) - => ElementType(elementType, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention); + IConventionElementTypeBuilder? IConventionPropertyBuilder.SetElementType(bool elementType, bool fromDataAnnotation) + => SetElementType(elementType, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs b/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs index aa4a3b435e3..9e13e940d68 100644 --- a/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs @@ -333,7 +333,7 @@ public static bool IsCompatible(MemberInfo? newMemberInfo, PropertyBase existing { var builder = Property(propertyType, propertyName, memberInfo, typeConfigurationSource, configurationSource); - builder?.ElementType(true, configurationSource!.Value); + builder?.SetElementType(true, configurationSource!.Value); return builder; } diff --git a/src/EFCore/Metadata/Internal/Property.cs b/src/EFCore/Metadata/Internal/Property.cs index c7bd85acb51..73829eff60d 100644 --- a/src/EFCore/Metadata/Internal/Property.cs +++ b/src/EFCore/Metadata/Internal/Property.cs @@ -1205,8 +1205,8 @@ public virtual CoreTypeMapping? TypeMapping /// 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 IElementType? GetElementType() - => (IElementType?)this[CoreAnnotationNames.ElementType]; + public virtual ElementType? GetElementType() + => (ElementType?)this[CoreAnnotationNames.ElementType]; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -1214,7 +1214,7 @@ public virtual CoreTypeMapping? TypeMapping /// 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 IElementType? ElementType( + public virtual ElementType? SetElementType( bool elementType, ConfigurationSource configurationSource) { @@ -1235,7 +1235,7 @@ public virtual CoreTypeMapping? TypeMapping if (existingElementType != null && !elementType) { - ((ElementType)existingElementType).SetRemovedFromModel(); + existingElementType.SetRemovedFromModel(); RemoveAnnotation(CoreAnnotationNames.ElementType); OnElementTypeSet(null, existingElementType); return null; @@ -1393,6 +1393,16 @@ IConventionPropertyBuilder IConventionProperty.Builder get => Builder; } + /// + /// 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. + /// + [DebuggerStepThrough] + IReadOnlyElementType? IReadOnlyProperty.GetElementType() + => GetElementType(); + /// /// 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 @@ -2007,8 +2017,8 @@ void IMutableProperty.SetJsonValueReaderWriterType(Type? readerWriterType) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [DebuggerStepThrough] - IElementType? IConventionProperty.ElementType(bool elementType, bool fromDataAnnotation) - => ElementType( + IConventionElementType? IConventionProperty.SetElementType(bool elementType, bool fromDataAnnotation) + => SetElementType( elementType, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention); @@ -2019,6 +2029,36 @@ void IMutableProperty.SetJsonValueReaderWriterType(Type? readerWriterType) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [DebuggerStepThrough] - void IMutableProperty.ElementType(bool elementType) - => ElementType(elementType, ConfigurationSource.Explicit); + void IMutableProperty.SetElementType(bool elementType) + => SetElementType(elementType, ConfigurationSource.Explicit); + + /// + /// 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. + /// + [DebuggerStepThrough] + IMutableElementType? IMutableProperty.GetElementType() + => GetElementType(); + + /// + /// 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. + /// + [DebuggerStepThrough] + IElementType? IProperty.GetElementType() + => GetElementType(); + + /// + /// 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. + /// + [DebuggerStepThrough] + IConventionElementType? IConventionProperty.GetElementType() + => GetElementType(); } diff --git a/src/EFCore/Metadata/Internal/PropertyAccessorsFactory.cs b/src/EFCore/Metadata/Internal/PropertyAccessorsFactory.cs index 6abbbd08aec..2c2686a453e 100644 --- a/src/EFCore/Metadata/Internal/PropertyAccessorsFactory.cs +++ b/src/EFCore/Metadata/Internal/PropertyAccessorsFactory.cs @@ -42,12 +42,12 @@ private static PropertyAccessors CreateGeneric(IPropertyBase property property == null ? null : CreateValueBufferGetter(property)); } - private static Func CreateCurrentValueGetter( + private static Func CreateCurrentValueGetter( IPropertyBase propertyBase, bool useStoreGeneratedValues) { var entityClrType = propertyBase.DeclaringType.ContainingEntityType.ClrType; - var entryParameter = Expression.Parameter(typeof(IInternalEntry), "entry"); + var entryParameter = Expression.Parameter(typeof(InternalEntityEntry), "entry"); var propertyIndex = propertyBase.GetIndex(); var shadowIndex = propertyBase.GetShadowIndex(); var storeGeneratedIndex = propertyBase.GetStoreGeneratedIndex(); @@ -66,7 +66,7 @@ private static Func CreateCurrentValueGetter CreateCurrentValueGetter>( + return Expression.Lambda>( currentValueExpression, entryParameter) .Compile(); } - private static Func CreateOriginalValueGetter(IProperty property) + private static Func CreateOriginalValueGetter(IProperty property) { - var entryParameter = Expression.Parameter(typeof(IInternalEntry), "entry"); + var entryParameter = Expression.Parameter(typeof(InternalEntityEntry), "entry"); var originalValuesIndex = property.GetOriginalValueIndex(); - return Expression.Lambda>( + return Expression.Lambda>( originalValuesIndex >= 0 ? Expression.Call( entryParameter, diff --git a/src/EFCore/Metadata/ParameterBindingInfo.cs b/src/EFCore/Metadata/ParameterBindingInfo.cs index c2a011455c0..034a02f5eed 100644 --- a/src/EFCore/Metadata/ParameterBindingInfo.cs +++ b/src/EFCore/Metadata/ParameterBindingInfo.cs @@ -17,7 +17,7 @@ public readonly struct ParameterBindingInfo /// The entity or complex type for this binding. /// The expression tree from which the parameter value will come. public ParameterBindingInfo( - IEntityType structuralType, + ITypeBase structuralType, Expression materializationContextExpression) { Check.NotNull(structuralType, nameof(structuralType)); diff --git a/src/EFCore/Metadata/RuntimeEntityType.cs b/src/EFCore/Metadata/RuntimeEntityType.cs index bf51b042def..23d85a2b61b 100644 --- a/src/EFCore/Metadata/RuntimeEntityType.cs +++ b/src/EFCore/Metadata/RuntimeEntityType.cs @@ -53,8 +53,8 @@ private readonly SortedDictionary _triggers private Func? _relationshipSnapshotFactory; private IProperty[]? _foreignKeyProperties; private IProperty[]? _valueGeneratingProperties; - private Func? _originalValuesFactory; - private Func? _temporaryValuesFactory; + private Func? _originalValuesFactory; + private Func? _temporaryValuesFactory; private Func? _storeGeneratedValuesFactory; private Func? _shadowValuesFactory; private Func? _emptyShadowValuesFactory; @@ -1293,7 +1293,7 @@ PropertyAccessMode IReadOnlyEntityType.GetNavigationAccessMode() /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [EntityFrameworkInternal] - public virtual void SetOriginalValuesFactory(Func factory) + public virtual void SetOriginalValuesFactory(Func factory) => _originalValuesFactory = factory; /// @@ -1313,7 +1313,7 @@ public virtual void SetStoreGeneratedValuesFactory(Func factory) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [EntityFrameworkInternal] - public virtual void SetTemporaryValuesFactory(Func factory) + public virtual void SetTemporaryValuesFactory(Func factory) => _temporaryValuesFactory = factory; /// @@ -1343,7 +1343,7 @@ public virtual void SetEmptyShadowValuesFactory(Func factory) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [EntityFrameworkInternal] - public virtual Func OriginalValuesFactory + public virtual Func OriginalValuesFactory => NonCapturingLazyInitializer.EnsureInitialized( ref _originalValuesFactory, this, static complexType => RuntimeFeature.IsDynamicCodeSupported @@ -1371,7 +1371,7 @@ public virtual Func StoreGeneratedValuesFactory /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [EntityFrameworkInternal] - public virtual Func TemporaryValuesFactory + public virtual Func TemporaryValuesFactory => NonCapturingLazyInitializer.EnsureInitialized( ref _temporaryValuesFactory, this, static complexType => RuntimeFeature.IsDynamicCodeSupported diff --git a/src/EFCore/Metadata/RuntimeProperty.cs b/src/EFCore/Metadata/RuntimeProperty.cs index 6bdcfcc03cc..f2ec1db2445 100644 --- a/src/EFCore/Metadata/RuntimeProperty.cs +++ b/src/EFCore/Metadata/RuntimeProperty.cs @@ -325,6 +325,10 @@ public virtual DebugView DebugView public override string ToString() => ((IReadOnlyProperty)this).ToDebugString(MetadataDebugStringOptions.SingleLineDefault); + /// + IReadOnlyElementType? IReadOnlyProperty.GetElementType() + => GetElementType(); + /// bool IReadOnlyProperty.IsNullable { diff --git a/src/EFCore/Storage/CoreTypeMapping.cs b/src/EFCore/Storage/CoreTypeMapping.cs index cf4a0030871..8553c639604 100644 --- a/src/EFCore/Storage/CoreTypeMapping.cs +++ b/src/EFCore/Storage/CoreTypeMapping.cs @@ -272,7 +272,7 @@ public virtual ValueComparer ProviderValueComparer /// The element mapping, or for non-collection mappings. /// The JSON reader/writer, or to leave unchanged. /// A new type mapping - public abstract CoreTypeMapping Clone( + public abstract CoreTypeMapping WithComposedConverter( ValueConverter? converter, ValueComparer? comparer = null, ValueComparer? keyComparer = null, diff --git a/src/EFCore/Storage/Json/JsonWarningEnumReaderWriter.cs b/src/EFCore/Storage/Json/JsonWarningEnumReaderWriter.cs index 3e38ae9d11c..aed1c3e9cc9 100644 --- a/src/EFCore/Storage/Json/JsonWarningEnumReaderWriter.cs +++ b/src/EFCore/Storage/Json/JsonWarningEnumReaderWriter.cs @@ -29,7 +29,7 @@ public override TEnum FromJsonTyped(ref Utf8JsonReaderManager manager, object? e { if (manager.CurrentReader.TokenType == JsonTokenType.String) { - if (manager.QueryLogger?.Options.ShouldWarnForEnumType(typeof(TEnum)) == true) + if (manager.QueryLogger?.Options.ShouldWarnForStringEnumValueInJson(typeof(TEnum)) == true) { manager.QueryLogger.StringEnumValueInJson(typeof(TEnum)); } diff --git a/src/EFCore/Storage/TypeMappingSource.cs b/src/EFCore/Storage/TypeMappingSource.cs index 4edbd91de83..a1e29021e52 100644 --- a/src/EFCore/Storage/TypeMappingSource.cs +++ b/src/EFCore/Storage/TypeMappingSource.cs @@ -131,7 +131,7 @@ protected TypeMappingSource(TypeMappingSourceDependencies dependencies) if (mapping != null) { - mapping = mapping.Clone( + mapping = mapping.WithComposedConverter( secondConverterInfo.Create(), jsonValueReaderWriter: mappingInfoUsed.JsonValueReaderWriter); break; @@ -141,7 +141,7 @@ protected TypeMappingSource(TypeMappingSourceDependencies dependencies) if (mapping != null) { - mapping = mapping.Clone( + mapping = mapping.WithComposedConverter( converterInfo.Create(), jsonValueReaderWriter: mappingInfo.JsonValueReaderWriter); break; @@ -160,7 +160,7 @@ protected TypeMappingSource(TypeMappingSourceDependencies dependencies) if (mapping != null && customConverter != null) { - mapping = mapping.Clone( + mapping = mapping.WithComposedConverter( customConverter, jsonValueReaderWriter: mappingInfo.JsonValueReaderWriter); } @@ -197,7 +197,7 @@ protected TypeMappingSource(TypeMappingSourceDependencies dependencies) info.WithConverter( // Note that the converter info is only used temporarily here and never creates an instance. new ValueConverterInfo(modelType, typeof(string), _ => null!)))! - .Clone( + .WithComposedConverter( (ValueConverter)Activator.CreateInstance( typeof(CollectionToJsonStringConverter<>).MakeGenericType(elementType), collectionReaderWriter!)!, comparer, diff --git a/src/EFCore/Storage/ValueConversion/ConverterMappingHints.cs b/src/EFCore/Storage/ValueConversion/ConverterMappingHints.cs index 9076f4c0eb3..829ddbda7a0 100644 --- a/src/EFCore/Storage/ValueConversion/ConverterMappingHints.cs +++ b/src/EFCore/Storage/ValueConversion/ConverterMappingHints.cs @@ -59,7 +59,7 @@ public virtual ConverterMappingHints With(ConverterMappingHints? hints) #pragma warning disable CS0612 // Type or member is obsolete hints.ValueGeneratorFactory ?? ValueGeneratorFactory) #pragma warning restore CS0612 // Type or member is obsolete - : hints.Override(this); + : hints.OverrideWith(this); /// /// Adds hints from the given object to this one. Hints that are already specified are overridden. @@ -69,7 +69,7 @@ public virtual ConverterMappingHints With(ConverterMappingHints? hints) /// /// The hints to add. /// The combined hints. - public virtual ConverterMappingHints Override(ConverterMappingHints? hints) + public virtual ConverterMappingHints OverrideWith(ConverterMappingHints? hints) => hints == null ? this : GetType().IsAssignableFrom(hints.GetType()) diff --git a/src/EFCore/Update/UpdateEntryExtensions.cs b/src/EFCore/Update/UpdateEntryExtensions.cs index 9e06e370a2d..99dcb989903 100644 --- a/src/EFCore/Update/UpdateEntryExtensions.cs +++ b/src/EFCore/Update/UpdateEntryExtensions.cs @@ -25,25 +25,6 @@ public static class UpdateEntryExtensions /// The property to get the value for. /// The value for the property. public static object? GetCurrentProviderValue(this IUpdateEntry updateEntry, IProperty property) - => GetCurrentProviderValue((IInternalEntry)updateEntry, property); - - /// - /// Gets the original value that was assigned to the property and converts it to the provider-expected value. - /// - /// The entry. - /// The property to get the value for. - /// The value for the property. - public static object? GetOriginalProviderValue(this IUpdateEntry updateEntry, IProperty property) - => GetOriginalProviderValue((IInternalEntry)updateEntry, property); - - /// - /// 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. - /// - [EntityFrameworkInternal] - public static object? GetCurrentProviderValue(this IInternalEntry updateEntry, IProperty property) { var value = updateEntry.GetCurrentValue(property); var typeMapping = property.GetTypeMapping(); @@ -61,13 +42,12 @@ public static class UpdateEntryExtensions } /// - /// 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. + /// Gets the original value that was assigned to the property and converts it to the provider-expected value. /// - [EntityFrameworkInternal] - public static object? GetOriginalProviderValue(this IInternalEntry updateEntry, IProperty property) + /// The entry. + /// The property to get the value for. + /// The value for the property. + public static object? GetOriginalProviderValue(this IUpdateEntry updateEntry, IProperty property) { var value = updateEntry.GetOriginalValue(property); var typeMapping = property.GetTypeMapping(); @@ -324,31 +304,6 @@ void AppendRelatedKey(IEntityType targetType, object value) public static string BuildCurrentValuesString( this IUpdateEntry entry, IEnumerable properties) - => BuildCurrentValuesString((IInternalEntry)entry, properties); - - /// - /// Creates a formatted string representation of the given properties and their original - /// values such as is useful when throwing exceptions about keys, indexes, etc. that use - /// the properties. - /// - /// The entry from which values will be obtained. - /// The properties to format. - /// The string representation. - public static string BuildOriginalValuesString( - this IUpdateEntry entry, - IEnumerable properties) - => BuildOriginalValuesString((IInternalEntry)entry, properties); - - /// - /// 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. - /// - [EntityFrameworkInternal] - public static string BuildCurrentValuesString( - this IInternalEntry entry, - IEnumerable properties) => "{" + string.Join( ", ", properties.Select( @@ -364,14 +319,15 @@ public static string BuildCurrentValuesString( + "}"; /// - /// 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. + /// Creates a formatted string representation of the given properties and their original + /// values such as is useful when throwing exceptions about keys, indexes, etc. that use + /// the properties. /// - [EntityFrameworkInternal] + /// The entry from which values will be obtained. + /// The properties to format. + /// The string representation. public static string BuildOriginalValuesString( - this IInternalEntry entry, + this IUpdateEntry entry, IEnumerable properties) => "{" + string.Join( diff --git a/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs b/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs index 1cb19610735..1eb3ef7d558 100644 --- a/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs +++ b/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs @@ -1372,7 +1372,7 @@ public void Validate(IDbContextOptions options) public WarningsConfiguration WarningsConfiguration => null; - public virtual bool ShouldWarnForEnumType(Type type) + public virtual bool ShouldWarnForStringEnumValueInJson(Type enumType) => true; } diff --git a/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs b/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs index 5a800c36ce2..d97d869037e 100644 --- a/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs +++ b/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs @@ -74,7 +74,7 @@ public virtual void Create_and_clone_with_converter(Type mappingType, Type type) protected static RelationalTypeMapping AssertClone(Type type, RelationalTypeMapping mapping) { - var clone = mapping.Clone("", null); + var clone = mapping.WithStoreTypeAndSize("", null); Assert.NotSame(mapping, clone); Assert.Same(mapping.GetType(), clone.GetType()); @@ -89,7 +89,7 @@ protected static RelationalTypeMapping AssertClone(Type type, RelationalTypeMapp Assert.Equal(StoreTypePostfix.PrecisionAndScale, clone.StoreTypePostfix); var newConverter = CreateConverter(typeof(object), type); - clone = (RelationalTypeMapping)mapping.Clone(newConverter); + clone = (RelationalTypeMapping)mapping.WithComposedConverter(newConverter); Assert.NotSame(mapping, clone); Assert.Same(mapping.GetType(), clone.GetType()); @@ -130,7 +130,7 @@ protected virtual void ConversionCloneTest( null, null); - var clone = mapping.Clone("", 66); + var clone = mapping.WithStoreTypeAndSize("", 66); Assert.NotSame(mapping, clone); Assert.Same(mapping.GetType(), clone.GetType()); @@ -150,7 +150,7 @@ protected virtual void ConversionCloneTest( Assert.Equal(StoreTypePostfix.Size, clone.StoreTypePostfix); var newConverter = CreateConverter(typeof(object), type); - clone = (RelationalTypeMapping)mapping.Clone(newConverter); + clone = (RelationalTypeMapping)mapping.WithComposedConverter(newConverter); Assert.NotSame(mapping, clone); Assert.Same(mapping.GetType(), clone.GetType()); @@ -194,7 +194,7 @@ protected virtual void UnicodeConversionCloneTest( null, null); - var clone = mapping.Clone("", 66); + var clone = mapping.WithStoreTypeAndSize("", 66); Assert.NotSame(mapping, clone); Assert.Same(mapping.GetType(), clone.GetType()); @@ -216,7 +216,7 @@ protected virtual void UnicodeConversionCloneTest( Assert.Equal(StoreTypePostfix.Size, clone.StoreTypePostfix); var newConverter = CreateConverter(typeof(object), type); - clone = (RelationalTypeMapping)mapping.Clone(newConverter); + clone = (RelationalTypeMapping)mapping.WithComposedConverter(newConverter); Assert.NotSame(mapping, clone); Assert.Same(mapping.GetType(), clone.GetType()); diff --git a/test/EFCore.Relational.Tests/TestUtilities/TestRelationalTypeMappingSource.cs b/test/EFCore.Relational.Tests/TestUtilities/TestRelationalTypeMappingSource.cs index 434f491c029..cd8ec9d7bb4 100644 --- a/test/EFCore.Relational.Tests/TestUtilities/TestRelationalTypeMappingSource.cs +++ b/test/EFCore.Relational.Tests/TestUtilities/TestRelationalTypeMappingSource.cs @@ -220,7 +220,7 @@ protected override RelationalTypeMapping FindMapping(in RelationalTypeMappingInf { return storeTypeName != null && !mapping.StoreType.Equals(storeTypeName, StringComparison.Ordinal) - ? mapping.Clone(storeTypeName, mapping.Size) + ? mapping.WithStoreTypeAndSize(storeTypeName, mapping.Size) : mapping; } } diff --git a/test/EFCore.SqlServer.FunctionalTests/EverythingIsBytesSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/EverythingIsBytesSqlServerTest.cs index 47dd77b4bb5..23ff5ea5552 100644 --- a/test/EFCore.SqlServer.FunctionalTests/EverythingIsBytesSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/EverythingIsBytesSqlServerTest.cs @@ -281,7 +281,7 @@ public SqlServerBytesTypeMappingSource( } protected override RelationalTypeMapping FindMapping(in RelationalTypeMappingInfo mappingInfo) - => FindRawMapping(mappingInfo)?.Clone(mappingInfo); + => FindRawMapping(mappingInfo)?.WithTypeMappingInfo(mappingInfo); private RelationalTypeMapping FindRawMapping(RelationalTypeMappingInfo mappingInfo) { diff --git a/test/EFCore.SqlServer.FunctionalTests/EverythingIsStringsSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/EverythingIsStringsSqlServerTest.cs index 9b0730c98f3..d86bf3b596f 100644 --- a/test/EFCore.SqlServer.FunctionalTests/EverythingIsStringsSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/EverythingIsStringsSqlServerTest.cs @@ -287,7 +287,7 @@ public SqlServerStringsTypeMappingSource( } protected override RelationalTypeMapping FindMapping(in RelationalTypeMappingInfo mappingInfo) - => FindRawMapping(mappingInfo)?.Clone(mappingInfo); + => FindRawMapping(mappingInfo)?.WithTypeMappingInfo(mappingInfo); private RelationalTypeMapping FindRawMapping(RelationalTypeMappingInfo mappingInfo) { diff --git a/test/EFCore.SqlServer.FunctionalTests/JsonTypesCustomMappingSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/JsonTypesCustomMappingSqlServerTest.cs index 6cee8193491..e4cbe5e9940 100644 --- a/test/EFCore.SqlServer.FunctionalTests/JsonTypesCustomMappingSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/JsonTypesCustomMappingSqlServerTest.cs @@ -65,7 +65,7 @@ private class TestSqlServerTypeMappingSource( info.WithConverter( // Note that the converter info is only used temporarily here and never creates an instance. new ValueConverterInfo(modelType, typeof(string), _ => null!)))! - .Clone( + .WithComposedConverter( (ValueConverter)Activator.CreateInstance( typeof(CollectionToJsonStringConverter<>).MakeGenericType(elementType), collectionReaderWriter!)!, comparer, diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeographyFixture.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeographyFixture.cs index aaa65262e3b..9d7223bdf72 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeographyFixture.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeographyFixture.cs @@ -48,8 +48,8 @@ public ReplacementTypeMappingSource( protected override RelationalTypeMapping FindMapping(in RelationalTypeMappingInfo mappingInfo) => mappingInfo.ClrType == typeof(GeoPoint) ? ((RelationalTypeMapping)base.FindMapping(typeof(Point)) - .Clone(new GeoPointConverter(CreateGeometryServices().CreateGeometryFactory()))) - .Clone("geography", null) + .WithComposedConverter(new GeoPointConverter(CreateGeometryServices().CreateGeometryFactory()))) + .WithStoreTypeAndSize("geography", null) : base.FindMapping(mappingInfo); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeometryFixture.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeometryFixture.cs index 05bd58cabb9..f386e5b2b81 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeometryFixture.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeometryFixture.cs @@ -45,7 +45,7 @@ public ReplacementTypeMappingSource( protected override RelationalTypeMapping FindMapping(in RelationalTypeMappingInfo mappingInfo) => mappingInfo.ClrType == typeof(GeoPoint) ? ((RelationalTypeMapping)base.FindMapping(typeof(Point)) - .Clone(new GeoPointConverter())).Clone("geometry", null) + .WithComposedConverter(new GeoPointConverter())).WithStoreTypeAndSize("geometry", null) : base.FindMapping(mappingInfo); } } diff --git a/test/EFCore.SqlServer.Tests/Storage/SqlServerTypeMappingTest.cs b/test/EFCore.SqlServer.Tests/Storage/SqlServerTypeMappingTest.cs index fe7abf7c45a..c24eeac1338 100644 --- a/test/EFCore.SqlServer.Tests/Storage/SqlServerTypeMappingTest.cs +++ b/test/EFCore.SqlServer.Tests/Storage/SqlServerTypeMappingTest.cs @@ -135,7 +135,7 @@ public virtual void Create_and_clone_UDT_mapping_with_converter() 33, true); - var clone = (SqlServerUdtTypeMapping)mapping.Clone("", 66); + var clone = (SqlServerUdtTypeMapping)mapping.WithStoreTypeAndSize("", 66); Assert.NotSame(mapping, clone); Assert.Same(mapping.GetType(), clone.GetType()); @@ -158,7 +158,7 @@ public virtual void Create_and_clone_UDT_mapping_with_converter() Assert.Same(literalGenerator, clone.LiteralGenerator); var newConverter = CreateConverter(typeof(object)); - clone = (SqlServerUdtTypeMapping)mapping.Clone(newConverter); + clone = (SqlServerUdtTypeMapping)mapping.WithComposedConverter(newConverter); Assert.NotSame(mapping, clone); Assert.Same(mapping.GetType(), clone.GetType()); diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/SpatialQuerySqliteFixture.cs b/test/EFCore.Sqlite.FunctionalTests/Query/SpatialQuerySqliteFixture.cs index 7febcaca4cf..3c72998a8aa 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/SpatialQuerySqliteFixture.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/SpatialQuerySqliteFixture.cs @@ -54,8 +54,8 @@ public ReplacementTypeMappingSource( protected override RelationalTypeMapping FindMapping(in RelationalTypeMappingInfo mappingInfo) => mappingInfo.ClrType == typeof(GeoPoint) ? ((RelationalTypeMapping)base.FindMapping(typeof(Point)) - .Clone(new GeoPointConverter())) - .Clone("geometry", null) + .WithComposedConverter(new GeoPointConverter())) + .WithStoreTypeAndSize("geometry", null) : base.FindMapping(mappingInfo); } } diff --git a/test/EFCore.Sqlite.FunctionalTests/SqliteApiConsistencyTest.cs b/test/EFCore.Sqlite.FunctionalTests/SqliteApiConsistencyTest.cs index 44f972be99a..73c68a7e986 100644 --- a/test/EFCore.Sqlite.FunctionalTests/SqliteApiConsistencyTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/SqliteApiConsistencyTest.cs @@ -26,7 +26,6 @@ public class SqliteApiConsistencyFixture : ApiConsistencyFixtureBase typeof(SqliteDbContextOptionsBuilderExtensions), typeof(SqliteDbContextOptionsBuilder), typeof(SqlitePropertyBuilderExtensions), - typeof(SqlitePrimitiveCollectionBuilderExtensions) }; public override @@ -54,8 +53,6 @@ public override protected override void Initialize() { MirrorTypes.Add(typeof(SqlitePropertyBuilderExtensions), typeof(SqliteComplexTypePropertyBuilderExtensions)); - MirrorTypes.Add(typeof(SqlitePrimitiveCollectionBuilderExtensions), typeof(SqlitePropertyBuilderExtensions)); - MirrorTypes.Add(typeof(SqliteComplexTypePrimitiveCollectionBuilderExtensions), typeof(SqliteComplexTypePropertyBuilderExtensions)); base.Initialize(); } diff --git a/test/EFCore.Tests/ChangeTracking/Internal/ChangeDetectorTest.cs b/test/EFCore.Tests/ChangeTracking/Internal/ChangeDetectorTest.cs index 747fb8a21ec..7e4ff1dc769 100644 --- a/test/EFCore.Tests/ChangeTracking/Internal/ChangeDetectorTest.cs +++ b/test/EFCore.Tests/ChangeTracking/Internal/ChangeDetectorTest.cs @@ -311,7 +311,7 @@ public ConcreteTypeMapping(Type clrType, ValueConverter converter, ValueComparer { } - public override CoreTypeMapping Clone( + public override CoreTypeMapping WithComposedConverter( ValueConverter converter, ValueComparer comparer = null, ValueComparer keyComparer = null, diff --git a/test/EFCore.Tests/Metadata/Conventions/ConventionDispatcherTest.cs b/test/EFCore.Tests/Metadata/Conventions/ConventionDispatcherTest.cs index 177d4c9bbe4..b2364a55d22 100644 --- a/test/EFCore.Tests/Metadata/Conventions/ConventionDispatcherTest.cs +++ b/test/EFCore.Tests/Metadata/Conventions/ConventionDispatcherTest.cs @@ -3689,12 +3689,12 @@ public void OnPropertyElementTypeChanged_calls_conventions_in_order(bool useBuil if (useBuilder) { - Assert.NotNull(propertyBuilder.ElementType(true, ConfigurationSource.Convention)); + Assert.NotNull(propertyBuilder.SetElementType(true, ConfigurationSource.Convention)); elementType = (ElementType)propertyBuilder.Metadata.GetElementType()!; } else { - elementType = (ElementType)propertyBuilder.Metadata.ElementType(true, ConfigurationSource.Convention); + elementType = (ElementType)propertyBuilder.Metadata.SetElementType(true, ConfigurationSource.Convention); } if (useScope) @@ -3710,12 +3710,12 @@ public void OnPropertyElementTypeChanged_calls_conventions_in_order(bool useBuil if (useBuilder) { - Assert.Null(propertyBuilder.ElementType(true, ConfigurationSource.Convention)); + Assert.Null(propertyBuilder.SetElementType(true, ConfigurationSource.Convention)); elementType = (ElementType)propertyBuilder.Metadata.GetElementType()!; } else { - elementType = (ElementType)propertyBuilder.Metadata.ElementType(true, ConfigurationSource.Convention); + elementType = (ElementType)propertyBuilder.Metadata.SetElementType(true, ConfigurationSource.Convention); } Assert.Equal(new (object, object)[] { (null, elementType) }, convention1.Calls); @@ -3724,11 +3724,11 @@ public void OnPropertyElementTypeChanged_calls_conventions_in_order(bool useBuil if (useBuilder) { - Assert.NotNull(propertyBuilder.ElementType(false, ConfigurationSource.Convention)); + Assert.NotNull(propertyBuilder.SetElementType(false, ConfigurationSource.Convention)); } else { - Assert.Null(propertyBuilder.Metadata.ElementType(false, ConfigurationSource.Convention)); + Assert.Null(propertyBuilder.Metadata.SetElementType(false, ConfigurationSource.Convention)); } Assert.Equal(new (object, object)[] { (null, elementType), (elementType, null) }, convention1.Calls); @@ -5069,7 +5069,7 @@ public void OnElementTypeAnnotationChanged_calls_conventions_in_order(bool useBu var builder = new InternalModelBuilder(new Model(conventions)); var elementTypeBuilder = builder.Entity(typeof(SpecialOrder), ConfigurationSource.Convention)! .Property(nameof(SpecialOrder.OrderIds), ConfigurationSource.Convention)! - .ElementType(true, ConfigurationSource.Convention)!; + .SetElementType(true, ConfigurationSource.Convention)!; var scope = useScope ? builder.Metadata.ConventionDispatcher.DelayConventions() : null; @@ -5174,7 +5174,7 @@ public void OnElementTypeNullabilityChanged_calls_conventions_in_order(bool useB var builder = new InternalModelBuilder(model); var elementTypeBuilder = builder.Entity(typeof(SpecialOrder), ConfigurationSource.Convention)! .Property(nameof(SpecialOrder.Notes), ConfigurationSource.Convention)! - .ElementType(true, ConfigurationSource.Convention)!; + .SetElementType(true, ConfigurationSource.Convention)!; if (useBuilder) { diff --git a/test/EFCore.Tests/Metadata/Internal/ClrPropertyGetterFactoryTest.cs b/test/EFCore.Tests/Metadata/Internal/ClrPropertyGetterFactoryTest.cs index a0fe8d5f71d..666b80f7438 100644 --- a/test/EFCore.Tests/Metadata/Internal/ClrPropertyGetterFactoryTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/ClrPropertyGetterFactoryTest.cs @@ -19,16 +19,16 @@ public void Property_is_returned_if_it_implements_IClrPropertyGetter() private class FakeProperty : Annotatable, IProperty, IClrPropertyGetter { - public object GetClrValue(object entity) + public object GetClrValueUsingContainingEntity(object entity) => throw new NotImplementedException(); - public bool HasSentinel(object entity) + public bool HasSentinelUsingContainingEntity(object entity) => throw new NotImplementedException(); - public object GetStructuralTypeClrValue(object complexObject) + public object GetClrValue(object structuralObject) => throw new NotImplementedException(); - public bool HasStructuralTypeSentinelValue(object complexObject) + public bool HasSentinel(object structuralObject) => throw new NotImplementedException(); public IEnumerable GetContainingForeignKeys() @@ -88,6 +88,9 @@ public ValueComparer GetProviderValueComparer() public JsonValueReaderWriter GetJsonValueReaderWriter() => throw new NotImplementedException(); + IReadOnlyElementType IReadOnlyProperty.GetElementType() + => GetElementType(); + public IElementType GetElementType() => throw new NotImplementedException(); @@ -142,14 +145,14 @@ public void Delegate_getter_is_returned_for_IProperty_property() var idProperty = model.FindEntityType(typeof(Customer)).FindProperty(nameof(Customer.Id)); Assert.Equal( - 7, new ClrPropertyGetterFactory().Create(idProperty).GetClrValue( + 7, new ClrPropertyGetterFactory().Create(idProperty).GetClrValueUsingContainingEntity( new Customer { Id = 7 })); } [ConditionalFact] public void Delegate_getter_is_returned_for_property_info() => Assert.Equal( - 7, new ClrPropertyGetterFactory().Create(typeof(Customer).GetAnyProperty("Id")).GetClrValue( + 7, new ClrPropertyGetterFactory().Create(typeof(Customer).GetAnyProperty("Id")).GetClrValueUsingContainingEntity( new Customer { Id = 7 })); [ConditionalFact] @@ -162,7 +165,7 @@ public void Delegate_getter_is_returned_for_IProperty_struct_property() Assert.Equal( new Fuel(1.0), - new ClrPropertyGetterFactory().Create((IPropertyBase)fuelProperty).GetClrValue( + new ClrPropertyGetterFactory().Create((IPropertyBase)fuelProperty).GetClrValueUsingContainingEntity( new Customer { Id = 7, Fuel = new Fuel(1.0) })); } @@ -170,7 +173,7 @@ public void Delegate_getter_is_returned_for_IProperty_struct_property() public void Delegate_getter_is_returned_for_struct_property_info() => Assert.Equal( new Fuel(1.0), - new ClrPropertyGetterFactory().Create(typeof(Customer).GetAnyProperty("Fuel")).GetClrValue( + new ClrPropertyGetterFactory().Create(typeof(Customer).GetAnyProperty("Fuel")).GetClrValueUsingContainingEntity( new Customer { Id = 7, Fuel = new Fuel(1.0) })); [ConditionalFact] @@ -183,8 +186,8 @@ public void Delegate_getter_is_returned_for_index_property() modelBuilder.FinalizeModel(); Assert.Equal( - "ValueA", new ClrPropertyGetterFactory().Create((IPropertyBase)propertyA).GetClrValue(new IndexedClass { Id = 7 })); - Assert.Equal(123, new ClrPropertyGetterFactory().Create((IPropertyBase)propertyB).GetClrValue(new IndexedClass { Id = 7 })); + "ValueA", new ClrPropertyGetterFactory().Create((IPropertyBase)propertyA).GetClrValueUsingContainingEntity(new IndexedClass { Id = 7 })); + Assert.Equal(123, new ClrPropertyGetterFactory().Create((IPropertyBase)propertyB).GetClrValueUsingContainingEntity(new IndexedClass { Id = 7 })); } [ConditionalFact] @@ -205,11 +208,11 @@ public void Delegate_getter_is_returned_for_IProperty_complex_property() .ComplexType.FindProperty(nameof(Fuel.Volume))!; Assert.Equal( - 10.0, new ClrPropertyGetterFactory().Create(volumeProperty).GetClrValue( + 10.0, new ClrPropertyGetterFactory().Create(volumeProperty).GetClrValueUsingContainingEntity( new Customer { Id = 7, Fuel = new Fuel(10.0)})); Assert.Equal( - 10.0, new ClrPropertyGetterFactory().Create(volumeProperty).GetStructuralTypeClrValue(new Fuel(10.0))); + 10.0, new ClrPropertyGetterFactory().Create(volumeProperty).GetClrValue(new Fuel(10.0))); } private static TestHelpers.TestModelBuilder CreateModelBuilder() diff --git a/test/EFCore.Tests/Metadata/Internal/ClrPropertySetterFactoryTest.cs b/test/EFCore.Tests/Metadata/Internal/ClrPropertySetterFactoryTest.cs index 482694c17f7..b09e3299b77 100644 --- a/test/EFCore.Tests/Metadata/Internal/ClrPropertySetterFactoryTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/ClrPropertySetterFactoryTest.cs @@ -100,6 +100,9 @@ public ValueComparer GetProviderValueComparer() public JsonValueReaderWriter GetJsonValueReaderWriter() => throw new NotImplementedException(); + IReadOnlyElementType IReadOnlyProperty.GetElementType() + => GetElementType(); + public IElementType GetElementType() => throw new NotImplementedException();