From 6a53a384614072e921497abcb532bddba047f6ec Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Thu, 5 Oct 2023 13:12:19 +0100 Subject: [PATCH] Fix merge from 6.0 --- .../Extensions/CosmosPropertyExtensions.cs | 8 +- .../CosmosValueGenerationConvention.cs | 6 +- .../Internal/NavigationFixer.cs | 2 +- src/EFCore/Infrastructure/ModelValidator.cs | 13 ++- .../Conventions/RuntimeModelConvention.cs | 3 +- src/EFCore/Metadata/IReadOnlyEntityType.cs | 46 ++++------ src/EFCore/Metadata/IReadOnlyModel.cs | 18 ++-- src/EFCore/Metadata/Internal/EntityType.cs | 33 ++++--- src/EFCore/Metadata/Internal/Model.cs | 16 ++-- src/EFCore/Metadata/RuntimeEntityType.cs | 49 ++++++---- src/EFCore/Metadata/RuntimeModel.cs | 32 +++---- .../Internal/EntityMaterializerSource.cs | 91 +++++++++---------- .../ValueGeneration/ValueGeneratorCache.cs | 56 +++++++----- .../EmbeddedDocumentsTest.cs | 8 +- .../TestUtilities/CosmosTestStore.cs | 12 +-- .../CosmosModelValidatorTest.cs | 5 - .../SqlServerEndToEndTest.cs | 3 - .../Internal/KeyPropagatorTest.cs | 6 +- 18 files changed, 201 insertions(+), 206 deletions(-) diff --git a/src/EFCore.Cosmos/Extensions/CosmosPropertyExtensions.cs b/src/EFCore.Cosmos/Extensions/CosmosPropertyExtensions.cs index 2f96e92966e..1c57531d350 100644 --- a/src/EFCore.Cosmos/Extensions/CosmosPropertyExtensions.cs +++ b/src/EFCore.Cosmos/Extensions/CosmosPropertyExtensions.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Linq; using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal; // ReSharper disable once CheckNamespace @@ -18,7 +16,9 @@ namespace Microsoft.EntityFrameworkCore; public static class CosmosPropertyExtensions { private static readonly bool _useOldBehavior31664 = - AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31664", out var enabled31664) && enabled31664;/// + AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31664", out var enabled31664) && enabled31664; + + /// /// Returns the property name that the property is mapped to when targeting Cosmos. /// /// The property. @@ -39,7 +39,7 @@ private static string GetDefaultJsonPropertyName(IReadOnlyProperty property) if (pk != null && (property.ClrType == typeof(int) || ownership.Properties.Contains(property)) && (property.IsShadowProperty() || _useOldBehavior31664) - && pk.Properties.Count == ownership.Properties.Count + (ownership.IsUnique ? 0 : 1) + && pk.Properties.Count == ownership.Properties.Count + (ownership.IsUnique ? 0 : 1) && ownership.Properties.All(fkProperty => pk.Properties.Contains(fkProperty))) { return ""; diff --git a/src/EFCore.Cosmos/Metadata/Conventions/CosmosValueGenerationConvention.cs b/src/EFCore.Cosmos/Metadata/Conventions/CosmosValueGenerationConvention.cs index 628b41a8d30..0488a7851a9 100644 --- a/src/EFCore.Cosmos/Metadata/Conventions/CosmosValueGenerationConvention.cs +++ b/src/EFCore.Cosmos/Metadata/Conventions/CosmosValueGenerationConvention.cs @@ -18,7 +18,9 @@ public class CosmosValueGenerationConvention : IEntityTypeAnnotationChangedConvention { private static readonly bool _useOldBehavior31664 = - AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31664", out var enabled31664) && enabled31664;/// + AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31664", out var enabled31664) && enabled31664; + + /// /// Creates a new instance of . /// /// Parameter object containing dependencies for this convention. @@ -81,7 +83,7 @@ public virtual void ProcessEntityTypeAnnotationChanged( if (pk != null && !property.IsForeignKey() && pk.Properties.Count == ownership.Properties.Count + 1 - && (property.IsShadowProperty() || _useOldBehavior31664) + && (property.IsShadowProperty() || _useOldBehavior31664) && ownership.Properties.All(fkProperty => pk.Properties.Contains(fkProperty))) { return ValueGenerated.OnAddOrUpdate; diff --git a/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs b/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs index a871f65b241..7d1fa0ba890 100644 --- a/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs +++ b/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs @@ -1094,7 +1094,7 @@ private void FindOrCreateJoinEntry( else if (!_inAttachGraph) { var joinEntityType = arguments.SkipNavigation.JoinEntityType; - var joinEntity = _entityMaterializerSource.GetEmptyMaterializer(joinEntityType) + var joinEntity = joinEntityType.GetOrCreateEmptyMaterializer(_entityMaterializerSource) (new MaterializationContext(ValueBuffer.Empty, arguments.Entry.Context)); joinEntry = arguments.Entry.StateManager.GetOrCreateEntry(joinEntity, joinEntityType); diff --git a/src/EFCore/Infrastructure/ModelValidator.cs b/src/EFCore/Infrastructure/ModelValidator.cs index 583d1af8b07..220c2573fff 100644 --- a/src/EFCore/Infrastructure/ModelValidator.cs +++ b/src/EFCore/Infrastructure/ModelValidator.cs @@ -574,14 +574,13 @@ protected virtual void ValidateInheritanceMapping( protected virtual void ValidateDiscriminatorValues(IEntityType rootEntityType) { var derivedTypes = rootEntityType.GetDerivedTypesInclusive().ToList(); - - var discriminatorProperty = rootEntityType.FindDiscriminatorProperty(); - if (discriminatorProperty == null){ - if (derivedTypes.Count == 1) - { - return; - } + if (discriminatorProperty == null) + { + if (derivedTypes.Count == 1) + { + return; + } throw new InvalidOperationException( CoreStrings.NoDiscriminatorProperty(rootEntityType.DisplayName())); diff --git a/src/EFCore/Metadata/Conventions/RuntimeModelConvention.cs b/src/EFCore/Metadata/Conventions/RuntimeModelConvention.cs index 9c85bfe6225..ddedbb9cd57 100644 --- a/src/EFCore/Metadata/Conventions/RuntimeModelConvention.cs +++ b/src/EFCore/Metadata/Conventions/RuntimeModelConvention.cs @@ -44,7 +44,8 @@ public virtual IModel ProcessModelFinalized(IModel model) protected virtual RuntimeModel Create(IModel model) { var runtimeModel = new RuntimeModel(); - runtimeModel.ModelId = model.ModelId;runtimeModel.SetSkipDetectChanges(((IRuntimeModel)model).SkipDetectChanges); + runtimeModel.ModelId = model.ModelId; + runtimeModel.SetSkipDetectChanges(((IRuntimeModel)model).SkipDetectChanges); ((IModel)runtimeModel).ModelDependencies = model.ModelDependencies!; var entityTypes = model.GetEntityTypesInHierarchicalOrder(); diff --git a/src/EFCore/Metadata/IReadOnlyEntityType.cs b/src/EFCore/Metadata/IReadOnlyEntityType.cs index ed3b045326f..b87340e06aa 100644 --- a/src/EFCore/Metadata/IReadOnlyEntityType.cs +++ b/src/EFCore/Metadata/IReadOnlyEntityType.cs @@ -3,9 +3,6 @@ using System.Text; using Microsoft.EntityFrameworkCore.Metadata.Internal; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Metadata; @@ -765,6 +762,24 @@ IReadOnlyProperty GetProperty(string name) /// IEnumerable GetDeclaredTriggers(); + /// + /// 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] + Func GetOrCreateMaterializer(IEntityMaterializerSource source); + + /// + /// 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] + Func GetOrCreateEmptyMaterializer(IEntityMaterializerSource source); + /// /// /// Creates a human-readable representation of the given metadata. @@ -781,31 +796,6 @@ string ToDebugString(MetadataDebugStringOptions options = MetadataDebugStringOpt { var builder = new StringBuilder(); var indentString = new string(' ', indent); - /// - /// 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] - Func GetOrCreateMaterializer(IEntityMaterializerSource source); - - /// - /// - /// Creates a human-readable representation of the given metadata. - /// - /// - /// Warning: Do not rely on the format of the returned string. - /// It is designed for debugging only and may change arbitrarily between releases. - /// - /// - /// Options for generating the string. - /// The number of indent spaces to use before each new line. - /// A human-readable representation. - string ToDebugString(MetadataDebugStringOptions options = MetadataDebugStringOptions.ShortDefault, int indent = 0) - { - var builder = new StringBuilder(); - var indentString = new string(' ', indent); try { diff --git a/src/EFCore/Metadata/IReadOnlyModel.cs b/src/EFCore/Metadata/IReadOnlyModel.cs index 965dbeed542..4d47cef288e 100644 --- a/src/EFCore/Metadata/IReadOnlyModel.cs +++ b/src/EFCore/Metadata/IReadOnlyModel.cs @@ -196,15 +196,15 @@ private static int GetDerivedLevel(Type? derivedType, Dictionary deri } /// - /// 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 Guid ModelId { 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. + /// + [EntityFrameworkInternal] + public Guid ModelId { get; } + + /// /// /// Creates a human-readable representation of the given metadata. /// diff --git a/src/EFCore/Metadata/Internal/EntityType.cs b/src/EFCore/Metadata/Internal/EntityType.cs index 36aefbbe701..239e0cffc5c 100644 --- a/src/EFCore/Metadata/Internal/EntityType.cs +++ b/src/EFCore/Metadata/Internal/EntityType.cs @@ -5,11 +5,6 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -3580,16 +3575,26 @@ private void UpdateServiceOnlyConstructorBindingConfigurationSource(Configuratio configurationSource.Max(_serviceOnlyConstructorBindingConfigurationSource); /// - /// 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 virtual Func GetOrCreateMaterializer(IEntityMaterializerSource source) - => source.GetMaterializer(this); + /// 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 virtual Func GetOrCreateMaterializer(IEntityMaterializerSource source) + => source.GetMaterializer(this); - #endregion + /// + /// 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 virtual Func GetOrCreateEmptyMaterializer(IEntityMaterializerSource source) + => source.GetEmptyMaterializer(this); + + #endregion #region Explicit interface implementations diff --git a/src/EFCore/Metadata/Internal/Model.cs b/src/EFCore/Metadata/Internal/Model.cs index a02c191a012..f75b75e592a 100644 --- a/src/EFCore/Metadata/Internal/Model.cs +++ b/src/EFCore/Metadata/Internal/Model.cs @@ -454,14 +454,14 @@ public virtual IEnumerable FindEntityTypes(Type type) } /// - /// 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 virtual Guid ModelId { get; } = Guid.NewGuid(); - - /// + /// 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 virtual Guid ModelId { get; } = Guid.NewGuid(); + + /// /// 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 diff --git a/src/EFCore/Metadata/RuntimeEntityType.cs b/src/EFCore/Metadata/RuntimeEntityType.cs index 82eb446b5f2..32edd4ef79b 100644 --- a/src/EFCore/Metadata/RuntimeEntityType.cs +++ b/src/EFCore/Metadata/RuntimeEntityType.cs @@ -5,11 +5,7 @@ using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; -using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.Internal; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Microsoft.EntityFrameworkCore.ValueGeneration; namespace Microsoft.EntityFrameworkCore.Metadata; @@ -70,7 +66,8 @@ private readonly SortedDictionary _triggers private Func? _emptyShadowValuesFactory; private IProperty[]? _foreignKeyProperties; private IProperty[]? _valueGeneratingProperties; - private Func? _materializer; + private Func? _materializer; + private Func? _emptyMaterializer; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -850,20 +847,34 @@ public virtual InstantiationBinding? ServiceOnlyConstructorBinding => type.FindIndexerProperty(); /// - /// 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 virtual Func GetOrCreateMaterializer(IEntityMaterializerSource source) - => EntityMaterializerSource.UseOldBehavior31866 - ? source.GetMaterializer(this) - : NonCapturingLazyInitializer.EnsureInitialized( - ref _materializer, this, source, - static (e, s) => s.GetMaterializer(e)); - - /// + /// 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 virtual Func GetOrCreateMaterializer(IEntityMaterializerSource source) + => EntityMaterializerSource.UseOldBehavior31866 + ? source.GetMaterializer(this) + : NonCapturingLazyInitializer.EnsureInitialized( + ref _materializer, this, source, + static (e, s) => s.GetMaterializer(e)); + + /// + /// 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 virtual Func GetOrCreateEmptyMaterializer(IEntityMaterializerSource source) + => EntityMaterializerSource.UseOldBehavior31866 + ? source.GetEmptyMaterializer(this) + : NonCapturingLazyInitializer.EnsureInitialized( + ref _emptyMaterializer, this, source, + static (e, s) => s.GetEmptyMaterializer(e)); + + /// /// Returns a string that represents the current object. /// /// A string that represents the current object. diff --git a/src/EFCore/Metadata/RuntimeModel.cs b/src/EFCore/Metadata/RuntimeModel.cs index 37bf70166f2..d49fd226e11 100644 --- a/src/EFCore/Metadata/RuntimeModel.cs +++ b/src/EFCore/Metadata/RuntimeModel.cs @@ -136,15 +136,15 @@ private IEnumerable FindEntityTypes(Type type) } /// - /// 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 virtual Guid ModelId { 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. + /// + [EntityFrameworkInternal] + public virtual Guid ModelId { get; set; } + + /// /// Adds configuration for a scalar type. /// /// The type of value the property will hold. @@ -311,14 +311,8 @@ IEnumerable IModel.GetTypeMappingConfigurations() => _typeConfigurations.Count == 0 ? null : _typeConfigurations.GetValueOrDefault(propertyType); - /// - ITypeMappingConfiguration? IModel.FindTypeMappingConfiguration(Type propertyType) - => _typeConfigurations.Count == 0 - ? null - : _typeConfigurations.GetValueOrDefault(propertyType); - - /// - Guid IReadOnlyModel.ModelId - => ModelId; - } + + /// + Guid IReadOnlyModel.ModelId + => ModelId; } diff --git a/src/EFCore/Query/Internal/EntityMaterializerSource.cs b/src/EFCore/Query/Internal/EntityMaterializerSource.cs index 01e66cfce7f..1ed8f9a376f 100644 --- a/src/EFCore/Query/Internal/EntityMaterializerSource.cs +++ b/src/EFCore/Query/Internal/EntityMaterializerSource.cs @@ -15,13 +15,14 @@ namespace Microsoft.EntityFrameworkCore.Query.Internal; public class EntityMaterializerSource : IEntityMaterializerSource { /// - /// 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 static readonly bool UseOldBehavior31866 = - AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31866", out var enabled31866) && enabled31866;private ConcurrentDictionary>? _materializers; + /// 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 static readonly bool UseOldBehavior31866 = + AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31866", out var enabled31866) && enabled31866;private ConcurrentDictionary>? _materializers; + private ConcurrentDictionary>? _emptyMaterializers; private readonly List _bindingInterceptors; private readonly IMaterializationInterceptor? _materializationInterceptor; @@ -385,12 +386,6 @@ var materializationContextParameter .Compile(); } } - return Expression.Lambda>( - self.CreateMaterializeExpression(e, "instance", materializationContextParameter), - materializationContextParameter) - .Compile(); - }, - this); private ConcurrentDictionary> EmptyMaterializers => LazyInitializer.EnsureInitialized( @@ -403,45 +398,47 @@ private ConcurrentDictionary> /// 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 GetEmptyMaterializer( - IEntityType entityType) - => EmptyMaterializers.GetOrAdd( - entityType, - static (e, self) => + public virtual Func GetEmptyMaterializer(IEntityType entityType) + { + return UseOldBehavior31866 + ? EmptyMaterializers.GetOrAdd(entityType, static (e, s) => CreateEmptyMaterializer(s, e), this) + : CreateEmptyMaterializer(this, entityType); + + static Func CreateEmptyMaterializer(EntityMaterializerSource self, IEntityType e) + { + var binding = e.ServiceOnlyConstructorBinding; + if (binding == null) { - var binding = e.ServiceOnlyConstructorBinding; + var _ = e.ConstructorBinding; + binding = e.ServiceOnlyConstructorBinding; if (binding == null) { - var _ = e.ConstructorBinding; - binding = e.ServiceOnlyConstructorBinding; - if (binding == null) - { - throw new InvalidOperationException(CoreStrings.NoParameterlessConstructor(e.DisplayName())); - } + throw new InvalidOperationException(CoreStrings.NoParameterlessConstructor(e.DisplayName())); } + } - binding = self.ModifyBindings(e, binding); - - var materializationContextExpression = Expression.Parameter(typeof(MaterializationContext), "mc"); - var bindingInfo = new ParameterBindingInfo(e, materializationContextExpression); - var constructorExpression = binding.CreateConstructorExpression(bindingInfo); - - return Expression.Lambda>( - self._materializationInterceptor == null - ? constructorExpression - : CreateInterceptionMaterializeExpression( - e, - "instance", - new HashSet(), - self._materializationInterceptor, - binding, - bindingInfo, - constructorExpression, - materializationContextExpression), - materializationContextExpression) - .Compile(); - }, - this); + binding = self.ModifyBindings(e, binding); + + var materializationContextExpression = Expression.Parameter(typeof(MaterializationContext), "mc"); + var bindingInfo = new ParameterBindingInfo(e, materializationContextExpression); + var constructorExpression = binding.CreateConstructorExpression(bindingInfo); + + return Expression.Lambda>( + self._materializationInterceptor == null + ? constructorExpression + : CreateInterceptionMaterializeExpression( + e, + "instance", + new HashSet(), + self._materializationInterceptor, + binding, + bindingInfo, + constructorExpression, + materializationContextExpression), + materializationContextExpression) + .Compile(); + } + } private InstantiationBinding ModifyBindings(IEntityType entityType, InstantiationBinding binding) { diff --git a/src/EFCore/ValueGeneration/ValueGeneratorCache.cs b/src/EFCore/ValueGeneration/ValueGeneratorCache.cs index a71dd810519..88ea5f27713 100644 --- a/src/EFCore/ValueGeneration/ValueGeneratorCache.cs +++ b/src/EFCore/ValueGeneration/ValueGeneratorCache.cs @@ -28,7 +28,9 @@ namespace Microsoft.EntityFrameworkCore.ValueGeneration; public class ValueGeneratorCache : IValueGeneratorCache { private static readonly bool _useOldBehavior31539 = - AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31539", out var enabled31539) && enabled31539;/// + AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31539", out var enabled31539) && enabled31539; + + /// /// Initializes a new instance of the class. /// /// Parameter object containing dependencies for this service. @@ -47,24 +49,28 @@ public ValueGeneratorCache(ValueGeneratorCacheDependencies dependencies) private readonly struct CacheKey : IEquatable { private readonly Guid _modelId; - private readonly string? _property; - private readonly string? _entityType;public CacheKey(IProperty property, IEntityType entityType) - {if (_useOldBehavior31539) - { - _modelId = default; - _property = null; - _entityType = null; - Property = property; - EntityType = entityType; - }else - { - _modelId = entityType.Model.ModelId; - _property = property.Name; - _entityType = entityType.Name; - Property = null; - EntityType = null; - } + private readonly string? _property; + private readonly string? _entityType; + + public CacheKey(IProperty property, IEntityType entityType) + { + if (_useOldBehavior31539) + { + _modelId = default; + _property = null; + _entityType = null; + Property = property; + EntityType = entityType; + } + else + { + _modelId = entityType.Model.ModelId; + _property = property.Name; + _entityType = entityType.Name; + Property = null; + EntityType = null; } + } public IProperty? Property { get; } @@ -72,19 +78,19 @@ public ValueGeneratorCache(ValueGeneratorCacheDependencies dependencies) public bool Equals(CacheKey other) => _useOldBehavior31539 - ? Property!.Equals(other.Property) && EntityType!.Equals(other.EntityType) - : (_property!.Equals(other._property, StringComparison.Ordinal) - && _entityType!.Equals(other._entityType, StringComparison.Ordinal) - && _modelId.Equals(other._modelId)); + ? Property!.Equals(other.Property) && EntityType!.Equals(other.EntityType) + : (_property!.Equals(other._property, StringComparison.Ordinal) + && _entityType!.Equals(other._entityType, StringComparison.Ordinal) + && _modelId.Equals(other._modelId)); public override bool Equals(object? obj) => obj is CacheKey cacheKey && Equals(cacheKey); public override int GetHashCode() => _useOldBehavior31539 - ? HashCode.Combine(Property!, EntityType!) - : HashCode.Combine(_property!, _entityType!, _modelId); - } + ? HashCode.Combine(Property!, EntityType!) + : HashCode.Combine(_property!, _entityType!, _modelId); + } /// /// Gets the existing value generator from the cache, or creates a new one if one is not present in diff --git a/test/EFCore.Cosmos.FunctionalTests/EmbeddedDocumentsTest.cs b/test/EFCore.Cosmos.FunctionalTests/EmbeddedDocumentsTest.cs index 97682a1fec4..1e8ef9a6ea7 100644 --- a/test/EFCore.Cosmos.FunctionalTests/EmbeddedDocumentsTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/EmbeddedDocumentsTest.cs @@ -122,8 +122,8 @@ public virtual async Task Can_manipulate_embedded_collections(bool useIds) { existingAddress1Person2.IdNotes = new List { - new NoteWithId { Content = "First note" }, - new NoteWithId { Content = "Second note" } + new NoteWithId { Id = 1, Content = "First note" }, + new NoteWithId { Id = 2, Content = "Second note" } }; } else @@ -236,7 +236,7 @@ public virtual async Task Can_manipulate_embedded_collections(bool useIds) { addedAddress3.IdNotes = new List { - new NoteWithId { Id = -1, Content = "Another note" } + new NoteWithId { Id = 1, Content = "Another note" } }; } else @@ -382,7 +382,7 @@ async Task AssertState(EmbeddedTransportationContext context) if (useIds) { Assert.Equal(1, addresses[2].IdNotes.Count); - Assert.Equal(1, addresses[2].IdNotes.First().Id); + Assert.Equal(4, addresses[2].IdNotes.First().Id); Assert.Equal("City note", addresses[2].IdNotes.First().Content); } else diff --git a/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosTestStore.cs b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosTestStore.cs index d24c02f62d8..9c0411604a4 100644 --- a/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosTestStore.cs +++ b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosTestStore.cs @@ -5,11 +5,6 @@ using Azure.Core; using Microsoft.Azure.Cosmos; using Microsoft.EntityFrameworkCore.Cosmos.Storage.Internal; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Update; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using ContainerProperties = Microsoft.Azure.Cosmos.ContainerProperties; @@ -565,8 +560,11 @@ public IEnumerable> GetSeedData(bool providerValues public IEnumerable GetServiceProperties() => throw new NotImplementedException(); - public Func GetOrCreateMaterializer(IEntityMaterializerSource source) - => throw new NotImplementedException(); + public Func GetOrCreateMaterializer(IEntityMaterializerSource source) + => throw new NotImplementedException(); + + public Func GetOrCreateEmptyMaterializer(IEntityMaterializerSource source) + => throw new NotImplementedException(); public IEnumerable GetSkipNavigations() => throw new NotImplementedException(); diff --git a/test/EFCore.Cosmos.Tests/Infrastructure/CosmosModelValidatorTest.cs b/test/EFCore.Cosmos.Tests/Infrastructure/CosmosModelValidatorTest.cs index 0465f8051a1..2199963c4a7 100644 --- a/test/EFCore.Cosmos.Tests/Infrastructure/CosmosModelValidatorTest.cs +++ b/test/EFCore.Cosmos.Tests/Infrastructure/CosmosModelValidatorTest.cs @@ -2,9 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.EntityFrameworkCore.Cosmos.Internal; -using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.EntityFrameworkCore.TestUtilities; -using Xunit; namespace Microsoft.EntityFrameworkCore.Infrastructure; @@ -342,8 +339,6 @@ public virtual void Passes_on_valid_concurrency_token() .ToContainer("Orders") .Property("_etag") .IsConcurrencyToken(); - - } [ConditionalFact] diff --git a/test/EFCore.SqlServer.FunctionalTests/SqlServerEndToEndTest.cs b/test/EFCore.SqlServer.FunctionalTests/SqlServerEndToEndTest.cs index 435336628f5..a354af53ae0 100644 --- a/test/EFCore.SqlServer.FunctionalTests/SqlServerEndToEndTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/SqlServerEndToEndTest.cs @@ -4,9 +4,6 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations.Schema; using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.TestUtilities; -using Xunit; // ReSharper disable StringStartsWithIsCultureSpecific // ReSharper disable VirtualMemberCallInConstructor diff --git a/test/EFCore.Tests/ChangeTracking/Internal/KeyPropagatorTest.cs b/test/EFCore.Tests/ChangeTracking/Internal/KeyPropagatorTest.cs index 464151e63a3..3443c2f7b6c 100644 --- a/test/EFCore.Tests/ChangeTracking/Internal/KeyPropagatorTest.cs +++ b/test/EFCore.Tests/ChangeTracking/Internal/KeyPropagatorTest.cs @@ -179,7 +179,7 @@ public async Task Identifying_foreign_key_value_is_generated_if_principal_key_no [InlineData(true, true)] public async Task Identifying_foreign_key_value_is_propagated_if_principal_key_is_generated(bool generateTemporary, bool async) { - var principal = new Product(); + var principal = new Product(); var dependent = new ProductDetail { Product = principal }; var contextServices = CreateContextServices(BuildModel(generateTemporary)); @@ -187,7 +187,7 @@ public async Task Identifying_foreign_key_value_is_propagated_if_principal_key_i var principalEntry = stateManager.GetOrCreateEntry(principal); principalEntry.SetEntityState(EntityState.Added); var dependentEntry = stateManager.GetOrCreateEntry(dependent); - var runtimeModel = contextServices.GetRequiredService(); + var runtimeModel = contextServices.GetRequiredService(); var principalProperty = runtimeModel.FindEntityType(typeof(Product))!.FindProperty(nameof(Product.Id))!; var dependentProperty = runtimeModel.FindEntityType(typeof(ProductDetail))!.FindProperty(nameof(ProductDetail.Id))!; var keyPropagator = contextServices.GetRequiredService(); @@ -199,7 +199,7 @@ public async Task Identifying_foreign_key_value_is_propagated_if_principal_key_i Assert.NotEqual(0, principalEntry[principalProperty]); Assert.Equal(generateTemporary, principalEntry.HasTemporaryValue(principalProperty)); Assert.NotEqual(0, dependentEntry[dependentProperty]); - Assert.True(dependentEntry.HasTemporaryValue(dependentProperty)); + Assert.Equal(generateTemporary, dependentEntry.HasTemporaryValue(dependentProperty)); Assert.Equal(principalEntry[principalProperty], dependentEntry[dependentProperty]); }