diff --git a/src/EFCore.Abstractions/IndexAttribute.cs b/src/EFCore.Abstractions/IndexAttribute.cs index 4b93178c115..21d1d8d2e00 100644 --- a/src/EFCore.Abstractions/IndexAttribute.cs +++ b/src/EFCore.Abstractions/IndexAttribute.cs @@ -19,10 +19,25 @@ public sealed class IndexAttribute : Attribute private bool? _isUnique; private bool[]? _isDescending; + /// + /// Initializes a new instance of the class. + /// + /// The first (or only) property in the index. + /// The additional properties which constitute the index, if any, in order. + public IndexAttribute(string propertyName, params string[] additionalPropertyNames) + { + Check.NotEmpty(propertyName, nameof(propertyName)); + Check.HasNoEmptyElements(additionalPropertyNames, nameof(additionalPropertyNames)); + + PropertyNames = new List { propertyName }; + ((List)PropertyNames).AddRange(additionalPropertyNames); + } + /// /// Initializes a new instance of the class. /// /// The properties which constitute the index, in order (there must be at least one). + [Obsolete("Use the other constructor")] public IndexAttribute(params string[] propertyNames) { Check.NotEmpty(propertyNames, nameof(propertyNames)); diff --git a/src/EFCore.Proxies/Proxies/Internal/ProxyBindingInterceptor.cs b/src/EFCore.Proxies/Proxies/Internal/ProxyBindingInterceptor.cs index e7f18acbe38..755c81311c8 100644 --- a/src/EFCore.Proxies/Proxies/Internal/ProxyBindingInterceptor.cs +++ b/src/EFCore.Proxies/Proxies/Internal/ProxyBindingInterceptor.cs @@ -36,8 +36,9 @@ public ProxyBindingInterceptor(IProxyFactory proxyFactory) /// 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 InstantiationBinding ModifyBinding(IEntityType entityType, string entityInstanceName, InstantiationBinding binding) + public virtual InstantiationBinding ModifyBinding(InstantiationBindingInterceptionData interceptionData, InstantiationBinding binding) { + var entityType = interceptionData.EntityType; var proxyType = _proxyFactory.CreateProxyType(entityType); if ((bool?)entityType.Model[ProxyAnnotationNames.LazyLoading] == true) diff --git a/src/EFCore/ChangeTracking/Internal/StateManager.cs b/src/EFCore/ChangeTracking/Internal/StateManager.cs index 28aa13a5a6c..98432da6569 100644 --- a/src/EFCore/ChangeTracking/Internal/StateManager.cs +++ b/src/EFCore/ChangeTracking/Internal/StateManager.cs @@ -781,6 +781,7 @@ public virtual bool ResolveToExistingEntry( { if (_resolutionInterceptor != null) { + var interceptionData = new IdentityResolutionInterceptionData(Context); var needsTracking = false; foreach (var key in newEntry.EntityType.GetKeys()) { @@ -788,7 +789,7 @@ public virtual bool ResolveToExistingEntry( if (existingEntry != null) { _resolutionInterceptor.UpdateTrackedInstance( - Context, + interceptionData, new EntityEntry(existingEntry), newEntry.Entity); diff --git a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs index bf0db1a61f1..50de58a35de 100644 --- a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs +++ b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs @@ -479,7 +479,7 @@ public static (Expression Query, QueryExpressionEventData? EventData) QueryCompi if (interceptor != null) { - return (interceptor.ProcessingQuery(queryExpression, eventData), eventData); + return (interceptor.QueryCompilationStarting(queryExpression, eventData), eventData); } } diff --git a/src/EFCore/Diagnostics/IIdentityResolutionInterceptor.cs b/src/EFCore/Diagnostics/IIdentityResolutionInterceptor.cs index f35aaf15400..0141c6bab5f 100644 --- a/src/EFCore/Diagnostics/IIdentityResolutionInterceptor.cs +++ b/src/EFCore/Diagnostics/IIdentityResolutionInterceptor.cs @@ -35,8 +35,8 @@ public interface IIdentityResolutionInterceptor : IInterceptor /// an already tracked instance. This method must apply any property values and relationship changes from the new instance /// into the existing instance. The new instance is then discarded. /// - /// The is use. + /// Contextual information about the identity resolution. /// The entry for the existing tracked entity instance. - /// The new entity instance, which will be discarded after this call. - void UpdateTrackedInstance(DbContext context, EntityEntry existingEntry, object newInstance); + /// The new entity instance, which will be discarded after this call. + void UpdateTrackedInstance(IdentityResolutionInterceptionData interceptionData, EntityEntry existingEntry, object newEntity); } diff --git a/src/EFCore/Diagnostics/IInstantiationBindingInterceptor.cs b/src/EFCore/Diagnostics/IInstantiationBindingInterceptor.cs index 53f7ee70e28..4727bcc929d 100644 --- a/src/EFCore/Diagnostics/IInstantiationBindingInterceptor.cs +++ b/src/EFCore/Diagnostics/IInstantiationBindingInterceptor.cs @@ -17,9 +17,8 @@ public interface IInstantiationBindingInterceptor : ISingletonInterceptor /// /// Returns a new for the given entity type, potentially modified from the given binding. /// - /// The entity type for which the binding is being used. - /// The name of the instance being materialized. + /// Contextual information about the binding. /// The current binding. /// A new binding. - InstantiationBinding ModifyBinding(IEntityType entityType, string entityInstanceName, InstantiationBinding binding); + InstantiationBinding ModifyBinding(InstantiationBindingInterceptionData interceptionData, InstantiationBinding binding); } diff --git a/src/EFCore/Diagnostics/IMaterializationInterceptor.cs b/src/EFCore/Diagnostics/IMaterializationInterceptor.cs index e3b37c915f5..9d506ae9fe9 100644 --- a/src/EFCore/Diagnostics/IMaterializationInterceptor.cs +++ b/src/EFCore/Diagnostics/IMaterializationInterceptor.cs @@ -37,24 +37,24 @@ InterceptionResult CreatingInstance(MaterializationInterceptionData mate /// any properties values not set by the constructor have been set. /// /// Contextual information about the materialization happening. - /// + /// /// The entity instance that has been created. /// This value is typically used as the return value for the implementation of this method. /// /// /// The entity instance that EF will use. /// An implementation of this method for any interceptor that is not attempting to change the instance used - /// must return the value passed in. + /// must return the value passed in. /// - object CreatedInstance(MaterializationInterceptionData materializationData, object instance) - => instance; + object CreatedInstance(MaterializationInterceptionData materializationData, object entity) + => entity; /// /// Called immediately before EF is going to set property values of an entity that has just been created. Note that property values /// set by the constructor will already have been set. /// /// Contextual information about the materialization happening. - /// The entity instance for which property values will be set. + /// The entity instance for which property values will be set. /// /// Represents the current result if one exists. /// This value will have set to if some previous @@ -67,22 +67,22 @@ object CreatedInstance(MaterializationInterceptionData materializationData, obje /// An implementation of this method for any interceptor that is not attempting to suppress /// setting property values must return the value passed in. /// - InterceptionResult InitializingInstance(MaterializationInterceptionData materializationData, object instance, InterceptionResult result) + InterceptionResult InitializingInstance(MaterializationInterceptionData materializationData, object entity, InterceptionResult result) => result; /// /// Called immediately after EF has set property values of an entity that has just been created. /// /// Contextual information about the materialization happening. - /// + /// /// The entity instance that has been created. /// This value is typically used as the return value for the implementation of this method. /// /// /// The entity instance that EF will use. /// An implementation of this method for any interceptor that is not attempting to change the instance used - /// must return the value passed in. + /// must return the value passed in. /// - object InitializedInstance(MaterializationInterceptionData materializationData, object instance) - => instance; + object InitializedInstance(MaterializationInterceptionData materializationData, object entity) + => entity; } diff --git a/src/EFCore/Diagnostics/IQueryExpressionInterceptor.cs b/src/EFCore/Diagnostics/IQueryExpressionInterceptor.cs index ad4e8cd5e74..f9c1bcbb130 100644 --- a/src/EFCore/Diagnostics/IQueryExpressionInterceptor.cs +++ b/src/EFCore/Diagnostics/IQueryExpressionInterceptor.cs @@ -28,36 +28,8 @@ public interface IQueryExpressionInterceptor : IInterceptor /// The query expression. /// Contextual information about the query environment. /// The query expression tree to continue with, which may have been changed by the interceptor. - Expression ProcessingQuery( + Expression QueryCompilationStarting( Expression queryExpression, QueryExpressionEventData eventData) => queryExpression; - - /// - /// Called when EF is about to compile the query delegate that will be used to execute the query. - /// - /// The query expression. - /// The expression that will be compiled into the execution delegate. - /// Contextual information about the query environment. - /// The return type of the execution delegate. - /// The expression that will be compiled into the execution delegate, which may have been changed by the interceptor. - Expression> CompilingQuery( - Expression queryExpression, - Expression> queryExecutorExpression, - QueryExpressionEventData eventData) - => queryExecutorExpression; - - /// - /// Called when EF is about to compile the query delegate that will be used to execute the query. - /// - /// The query expression. - /// Contextual information about the query environment. - /// The delegate that will be used to execute the query. - /// The return type of the execution delegate. - /// The delegate that will be used to execute the query, which may have been changed by the interceptor. - Func CompiledQuery( - Expression queryExpression, - QueryExpressionEventData eventData, - Func queryExecutor) - => queryExecutor; } diff --git a/src/EFCore/Diagnostics/IdentityResolutionInterceptionData.cs b/src/EFCore/Diagnostics/IdentityResolutionInterceptionData.cs new file mode 100644 index 00000000000..a32011ea420 --- /dev/null +++ b/src/EFCore/Diagnostics/IdentityResolutionInterceptionData.cs @@ -0,0 +1,27 @@ +// 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.Diagnostics; + +/// +/// A parameter object passed to methods. +/// +/// +/// See Logging, events, and diagnostics for more information and examples. +/// +public readonly struct IdentityResolutionInterceptionData +{ + /// + /// Constructs the parameter object. + /// + /// The in use. + public IdentityResolutionInterceptionData(DbContext context) + { + Context = context; + } + + /// + /// The current instance being used. + /// + public DbContext Context { get; } +} diff --git a/src/EFCore/Diagnostics/SkippingIdentityResolutionInterceptor.cs b/src/EFCore/Diagnostics/IgnoringIdentityResolutionInterceptor.cs similarity index 67% rename from src/EFCore/Diagnostics/SkippingIdentityResolutionInterceptor.cs rename to src/EFCore/Diagnostics/IgnoringIdentityResolutionInterceptor.cs index 97ed1a6a596..49e240c11be 100644 --- a/src/EFCore/Diagnostics/SkippingIdentityResolutionInterceptor.cs +++ b/src/EFCore/Diagnostics/IgnoringIdentityResolutionInterceptor.cs @@ -7,17 +7,17 @@ namespace Microsoft.EntityFrameworkCore.Diagnostics; /// A that ignores the new instance and retains property values from the existing /// tracked instance. /// -public class SkippingIdentityResolutionInterceptor : IIdentityResolutionInterceptor +public class IgnoringIdentityResolutionInterceptor : IIdentityResolutionInterceptor { /// /// Called when a attempts to track a new instance of an entity with the same primary key value as /// an already tracked instance. This implementation does nothing, such that property values from the existing tracked /// instance are retained. /// - /// The is use. + /// Contextual information about the identity resolution. /// The entry for the existing tracked entity instance. - /// The new entity instance, which will be discarded after this call. - public virtual void UpdateTrackedInstance(DbContext context, EntityEntry existingEntry, object newInstance) + /// The new entity instance, which will be discarded after this call. + public virtual void UpdateTrackedInstance(IdentityResolutionInterceptionData interceptionData, EntityEntry existingEntry, object newEntity) { } } diff --git a/src/EFCore/Diagnostics/InstantiationBindingInterceptionData.cs b/src/EFCore/Diagnostics/InstantiationBindingInterceptionData.cs new file mode 100644 index 00000000000..09fbe332eeb --- /dev/null +++ b/src/EFCore/Diagnostics/InstantiationBindingInterceptionData.cs @@ -0,0 +1,28 @@ +// 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.Diagnostics; + +/// +/// A parameter object passed to methods. +/// +/// +/// See Logging, events, and diagnostics for more information and examples. +/// +public readonly struct InstantiationBindingInterceptionData +{ + + /// + /// Constructs the parameter object. + /// + /// The entity type for which the binding is being used. + public InstantiationBindingInterceptionData(IEntityType entityType) + { + EntityType = entityType; + } + + /// + /// The entity type for which the binding is being used. + /// + public IEntityType EntityType { get; } +} diff --git a/src/EFCore/Diagnostics/Internal/IdentityResolutionInterceptorAggregator.cs b/src/EFCore/Diagnostics/Internal/IdentityResolutionInterceptorAggregator.cs index 09241cacb89..185ccc1beb0 100644 --- a/src/EFCore/Diagnostics/Internal/IdentityResolutionInterceptorAggregator.cs +++ b/src/EFCore/Diagnostics/Internal/IdentityResolutionInterceptorAggregator.cs @@ -24,11 +24,11 @@ public CompositeIdentityResolutionInterceptor(IEnumerable CreatingInstance( public object CreatedInstance( MaterializationInterceptionData materializationData, - object instance) + object entity) { for (var i = 0; i < _interceptors.Length; i++) { - instance = _interceptors[i].CreatedInstance(materializationData, instance); + entity = _interceptors[i].CreatedInstance(materializationData, entity); } - return instance; + return entity; } public InterceptionResult InitializingInstance( MaterializationInterceptionData materializationData, - object instance, + object entity, InterceptionResult result) { for (var i = 0; i < _interceptors.Length; i++) { - result = _interceptors[i].InitializingInstance(materializationData, instance, result); + result = _interceptors[i].InitializingInstance(materializationData, entity, result); } return result; @@ -67,14 +67,14 @@ public InterceptionResult InitializingInstance( public object InitializedInstance( MaterializationInterceptionData materializationData, - object instance) + object entity) { for (var i = 0; i < _interceptors.Length; i++) { - instance = _interceptors[i].InitializedInstance(materializationData, instance); + entity = _interceptors[i].InitializedInstance(materializationData, entity); } - return instance; + return entity; } } } diff --git a/src/EFCore/Diagnostics/Internal/QueryExpressionInterceptorAggregator.cs b/src/EFCore/Diagnostics/Internal/QueryExpressionInterceptorAggregator.cs index 52aebb850a6..e8f546be816 100644 --- a/src/EFCore/Diagnostics/Internal/QueryExpressionInterceptorAggregator.cs +++ b/src/EFCore/Diagnostics/Internal/QueryExpressionInterceptorAggregator.cs @@ -24,42 +24,16 @@ public CompositeQueryExpressionInterceptor(IEnumerable> CompilingQuery( - Expression queryExpression, - Expression> queryExecutorExpression, - QueryExpressionEventData eventData) - { - for (var i = 0; i < _interceptors.Length; i++) - { - queryExecutorExpression = _interceptors[i].CompilingQuery(queryExpression, queryExecutorExpression, eventData); - } - - return queryExecutorExpression; - } - - public Func CompiledQuery( - Expression queryExpression, - QueryExpressionEventData eventData, - Func queryExecutor) - { - for (var i = 0; i < _interceptors.Length; i++) - { - queryExecutor = _interceptors[i].CompiledQuery(queryExpression, eventData, queryExecutor); - } - - return queryExecutor; - } } } diff --git a/src/EFCore/Diagnostics/UpdatingIdentityResolutionInterceptor.cs b/src/EFCore/Diagnostics/UpdatingIdentityResolutionInterceptor.cs index 7488415f3ed..dbe6c9a4cf0 100644 --- a/src/EFCore/Diagnostics/UpdatingIdentityResolutionInterceptor.cs +++ b/src/EFCore/Diagnostics/UpdatingIdentityResolutionInterceptor.cs @@ -36,12 +36,12 @@ public UpdatingIdentityResolutionInterceptor( /// an already tracked instance. This implementation copies property values from the new entity instance into the /// tracked entity instance. /// - /// The is use. + /// Contextual information about the identity resolution. /// The entry for the existing tracked entity instance. - /// The new entity instance, which will be discarded after this call. - public virtual void UpdateTrackedInstance(DbContext context, EntityEntry existingEntry, object newInstance) + /// The new entity instance, which will be discarded after this call. + public virtual void UpdateTrackedInstance(IdentityResolutionInterceptionData interceptionData, EntityEntry existingEntry, object newEntity) { - var tempEntry = context.Entry(newInstance); + var tempEntry = interceptionData.Context.Entry(newEntity); if (existingEntry.State == EntityState.Added) { diff --git a/src/EFCore/Query/Internal/EntityMaterializerSource.cs b/src/EFCore/Query/Internal/EntityMaterializerSource.cs index ea809e9d3da..d2930ad4ca3 100644 --- a/src/EFCore/Query/Internal/EntityMaterializerSource.cs +++ b/src/EFCore/Query/Internal/EntityMaterializerSource.cs @@ -56,7 +56,7 @@ public virtual Expression CreateMaterializeExpression( throw new InvalidOperationException(CoreStrings.CannotMaterializeAbstractType(entityType.DisplayName())); } - var constructorBinding = ModifyBindings(entityType, entityInstanceName, entityType.ConstructorBinding!); + var constructorBinding = ModifyBindings(entityType, entityType.ConstructorBinding!); var bindingInfo = new ParameterBindingInfo( entityType, @@ -405,7 +405,7 @@ public virtual Func GetEmptyMaterializer( } } - binding = self.ModifyBindings(e, "v", binding); + binding = self.ModifyBindings(e, binding); var materializationContextExpression = Expression.Parameter(typeof(MaterializationContext), "mc"); var bindingInfo = new ParameterBindingInfo(e, materializationContextExpression); @@ -429,11 +429,12 @@ public virtual Func GetEmptyMaterializer( }, this); - private InstantiationBinding ModifyBindings(IEntityType entityType, string entityInstanceName, InstantiationBinding binding) + private InstantiationBinding ModifyBindings(IEntityType entityType, InstantiationBinding binding) { + var interceptionData = new InstantiationBindingInterceptionData(entityType); foreach (var bindingInterceptor in _bindingInterceptors) { - binding = bindingInterceptor.ModifyBinding(entityType, entityInstanceName, binding); + binding = bindingInterceptor.ModifyBinding(interceptionData, binding); } return binding; diff --git a/src/EFCore/Query/QueryCompilationContext.cs b/src/EFCore/Query/QueryCompilationContext.cs index c592d2bc74f..c83a7c74910 100644 --- a/src/EFCore/Query/QueryCompilationContext.cs +++ b/src/EFCore/Query/QueryCompilationContext.cs @@ -178,20 +178,9 @@ public virtual Func CreateQueryExecutor(Expressi query, QueryContextParameter); - if (_queryExpressionInterceptor != null) - { - queryExecutorExpression = _queryExpressionInterceptor.CompilingQuery( - queryAndEventData.Query, queryExecutorExpression, queryAndEventData.EventData!); - } - try { - var queryExecutor = queryExecutorExpression.Compile(); - - return _queryExpressionInterceptor != null - ? _queryExpressionInterceptor.CompiledQuery( - queryAndEventData.Query, queryAndEventData.EventData!, queryExecutor) - : queryExecutor; + return queryExecutorExpression.Compile(); } finally { diff --git a/test/EFCore.Specification.Tests/F1MaterializationInterceptor.cs b/test/EFCore.Specification.Tests/F1MaterializationInterceptor.cs index b02d15a9b83..162f6c8d183 100644 --- a/test/EFCore.Specification.Tests/F1MaterializationInterceptor.cs +++ b/test/EFCore.Specification.Tests/F1MaterializationInterceptor.cs @@ -87,25 +87,25 @@ public InterceptionResult CreatingInstance( _ => result }; - public object CreatedInstance(MaterializationInterceptionData materializationData, object instance) + public object CreatedInstance(MaterializationInterceptionData materializationData, object entity) { - Assert.True(instance is IF1Proxy); + Assert.True(entity is IF1Proxy); - ((IF1Proxy)instance).CreatedCalled = true; + ((IF1Proxy)entity).CreatedCalled = true; - return instance; + return entity; } public InterceptionResult InitializingInstance( MaterializationInterceptionData materializationData, - object instance, + object entity, InterceptionResult result) { - Assert.True(instance is IF1Proxy); + Assert.True(entity is IF1Proxy); - ((IF1Proxy)instance).InitializingCalled = true; + ((IF1Proxy)entity).InitializingCalled = true; - if (instance is Sponsor sponsor) + if (entity is Sponsor sponsor) { sponsor.Id = materializationData.GetPropertyValue(nameof(sponsor.Id)); sponsor.Name = "Intercepted: " + materializationData.GetPropertyValue(nameof(sponsor.Name)); @@ -116,17 +116,17 @@ public InterceptionResult InitializingInstance( return result; } - public object InitializedInstance(MaterializationInterceptionData materializationData, object instance) + public object InitializedInstance(MaterializationInterceptionData materializationData, object entity) { - Assert.True(instance is IF1Proxy); + Assert.True(entity is IF1Proxy); - ((IF1Proxy)instance).InitializedCalled = true; + ((IF1Proxy)entity).InitializedCalled = true; - if (instance is Sponsor.SponsorProxy sponsor) + if (entity is Sponsor.SponsorProxy sponsor) { return new Sponsor.SponsorDoubleProxy(sponsor); } - return instance; + return entity; } } diff --git a/test/EFCore.Specification.Tests/MaterializationInterceptionTestBase.cs b/test/EFCore.Specification.Tests/MaterializationInterceptionTestBase.cs index f4cd7c0f1c0..758da09e0ef 100644 --- a/test/EFCore.Specification.Tests/MaterializationInterceptionTestBase.cs +++ b/test/EFCore.Specification.Tests/MaterializationInterceptionTestBase.cs @@ -321,7 +321,7 @@ public TestBindingInterceptor(string id) protected Book BookFactory() => new() { MaterializedBy = _id }; - public InstantiationBinding ModifyBinding(IEntityType entityType, string entityInstanceName, InstantiationBinding binding) + public InstantiationBinding ModifyBinding(InstantiationBindingInterceptionData interceptionData, InstantiationBinding binding) { CalledCount++; @@ -329,7 +329,7 @@ public InstantiationBinding ModifyBinding(IEntityType entityType, string entityI this, typeof(TestBindingInterceptor).GetTypeInfo().GetDeclaredMethod(nameof(BookFactory))!, new List(), - entityType.ClrType); + interceptionData.EntityType.ClrType); } } @@ -352,27 +352,27 @@ public InterceptionResult CreatingInstance( } public object CreatedInstance( - MaterializationInterceptionData materializationData, object instance) + MaterializationInterceptionData materializationData, object entity) { - _validate(materializationData, instance, nameof(CreatedInstance)); + _validate(materializationData, entity, nameof(CreatedInstance)); - return instance; + return entity; } public InterceptionResult InitializingInstance( - MaterializationInterceptionData materializationData, object instance, InterceptionResult result) + MaterializationInterceptionData materializationData, object entity, InterceptionResult result) { - _validate(materializationData, instance, nameof(InitializingInstance)); + _validate(materializationData, entity, nameof(InitializingInstance)); return result; } public object InitializedInstance( - MaterializationInterceptionData materializationData, object instance) + MaterializationInterceptionData materializationData, object entity) { - _validate(materializationData, instance, nameof(InitializedInstance)); + _validate(materializationData, entity, nameof(InitializedInstance)); - return instance; + return entity; } } @@ -390,24 +390,24 @@ public InterceptionResult CreatingInstance( => result; public object CreatedInstance( - MaterializationInterceptionData materializationData, object instance) + MaterializationInterceptionData materializationData, object entity) { - ((Book)instance).CreatedBy += _id; - return instance; + ((Book)entity).CreatedBy += _id; + return entity; } public InterceptionResult InitializingInstance( - MaterializationInterceptionData materializationData, object instance, InterceptionResult result) + MaterializationInterceptionData materializationData, object entity, InterceptionResult result) { - ((Book)instance).InitializingBy += _id; + ((Book)entity).InitializingBy += _id; return result; } public object InitializedInstance( - MaterializationInterceptionData materializationData, object instance) + MaterializationInterceptionData materializationData, object entity) { - ((Book)instance).InitializedBy += _id; - return instance; + ((Book)entity).InitializedBy += _id; + return entity; } } } diff --git a/test/EFCore.Specification.Tests/PropertyValuesTestBase.cs b/test/EFCore.Specification.Tests/PropertyValuesTestBase.cs index d1374936e5f..6a7b67f389b 100644 --- a/test/EFCore.Specification.Tests/PropertyValuesTestBase.cs +++ b/test/EFCore.Specification.Tests/PropertyValuesTestBase.cs @@ -2436,49 +2436,49 @@ public InterceptionResult CreatingInstance( MaterializationInterceptionData materializationData, InterceptionResult result) => result; - public object CreatedInstance(MaterializationInterceptionData materializationData, object instance) + public object CreatedInstance(MaterializationInterceptionData materializationData, object entity) { - if (instance is IDictionary joinEntity) + if (entity is IDictionary joinEntity) { joinEntity["CreatedCalled"] = true; } else { - ((PropertyValuesBase)instance).CreatedCalled = true; + ((PropertyValuesBase)entity).CreatedCalled = true; } - return instance; + return entity; } public InterceptionResult InitializingInstance( MaterializationInterceptionData materializationData, - object instance, + object entity, InterceptionResult result) { - if (instance is IDictionary joinEntity) + if (entity is IDictionary joinEntity) { joinEntity["InitializingCalled"] = true; } else { - ((PropertyValuesBase)instance).InitializingCalled = true; + ((PropertyValuesBase)entity).InitializingCalled = true; } return result; } - public object InitializedInstance(MaterializationInterceptionData materializationData, object instance) + public object InitializedInstance(MaterializationInterceptionData materializationData, object entity) { - if (instance is IDictionary joinEntity) + if (entity is IDictionary joinEntity) { joinEntity["InitializedCalled"] = true; } else { - ((PropertyValuesBase)instance).InitializedCalled = true; + ((PropertyValuesBase)entity).InitializedCalled = true; } - return instance; + return entity; } } } diff --git a/test/EFCore.Specification.Tests/QueryExpressionInterceptionTestBase.cs b/test/EFCore.Specification.Tests/QueryExpressionInterceptionTestBase.cs index 83340269734..e761fcd0073 100644 --- a/test/EFCore.Specification.Tests/QueryExpressionInterceptionTestBase.cs +++ b/test/EFCore.Specification.Tests/QueryExpressionInterceptionTestBase.cs @@ -43,8 +43,8 @@ public virtual async Task Intercept_query_with_multiple_interceptors(bool async, { var interceptor1 = new TestQueryExpressionInterceptor(); var interceptor2 = new QueryChangingExpressionInterceptor(); - var interceptor3 = new QueryCompilationChangingExpressionInterceptor(); - var interceptor4 = new QueryCompilationDelegateChangingInterceptor(); + var interceptor3 = new TestQueryExpressionInterceptor(); + var interceptor4 = new TestQueryExpressionInterceptor(); using var context = CreateContext( new IInterceptor[] { new TestQueryExpressionInterceptor(), interceptor1, interceptor2 }, @@ -67,13 +67,7 @@ public virtual async Task Intercept_query_with_multiple_interceptors(bool async, CoreEventId.QueryCompilationStarting.Name, CoreEventId.QueryExecutionPlanned.Name); - Assert.Equal(1, interceptor3.ExecutionCount); - Assert.Equal(1, interceptor4.ExecutionCount); - _ = async ? await query.ToListAsync() : query.ToList(); - - Assert.Equal(2, interceptor3.ExecutionCount); - Assert.Equal(2, interceptor4.ExecutionCount); } [ConditionalTheory] @@ -100,10 +94,10 @@ public virtual async Task Intercept_to_change_query_expression(bool async, bool protected class QueryChangingExpressionInterceptor : TestQueryExpressionInterceptor { - public override Expression ProcessingQuery( + public override Expression QueryCompilationStarting( Expression queryExpression, QueryExpressionEventData eventData) - => base.ProcessingQuery(new SingularityTypeExpressionVisitor().Visit(queryExpression), eventData); + => base.QueryCompilationStarting(new SingularityTypeExpressionVisitor().Visit(queryExpression), eventData); private class SingularityTypeExpressionVisitor : ExpressionVisitor { @@ -114,151 +108,28 @@ protected override Expression VisitBinary(BinaryExpression node) } } - [ConditionalTheory] - [InlineData(false, false)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(true, true)] - public virtual async Task Intercept_to_change_query_compilation_expression(bool async, bool inject) - { - var (context, interceptor) = CreateContext(inject); - - using var __ = context; - - var query = context.Set().OrderBy(e => e.Type); - var results = async ? await query.ToListAsync() : query.ToList(); - - Assert.Equal(2, results.Count); - Assert.Equal("Bing Bang", results[0].Type); - Assert.Equal("Black Hole", results[1].Type); - - AssertNormalOutcome(context, interceptor); - Assert.Equal(1, interceptor.ExecutionCount); - - _ = async ? await query.ToListAsync() : query.ToList(); - - AssertNormalOutcome(context, interceptor); - Assert.Equal(2, interceptor.ExecutionCount); - } - - protected class QueryCompilationChangingExpressionInterceptor : TestQueryExpressionInterceptor - { - public int ExecutionCount { get; set; } - - public override Expression> CompilingQuery( - Expression queryExpression, - Expression> queryExecutorExpression, - QueryExpressionEventData eventData) - => base.CompilingQuery( - queryExpression, Expression.Lambda>( - Expression.Block( - Expression.Assign( - Expression.Property( - Expression.Constant(this), - nameof(ExecutionCount)), - Expression.Add( - Expression.Property( - Expression.Constant(this), - nameof(ExecutionCount)), - Expression.Constant(1))), - queryExecutorExpression.Body), - queryExecutorExpression.Parameters), - eventData); - } - - [ConditionalTheory] - [InlineData(false, false)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(true, true)] - public virtual async Task Intercept_to_change_query_compilation_delegate(bool async, bool inject) - { - var (context, interceptor) = CreateContext(inject); - - using var __ = context; - - var query = context.Set().OrderBy(e => e.Type); - var results = async ? await query.ToListAsync() : query.ToList(); - - Assert.Equal(2, results.Count); - Assert.Equal("Bing Bang", results[0].Type); - Assert.Equal("Black Hole", results[1].Type); - - AssertNormalOutcome(context, interceptor); - Assert.Equal(1, interceptor.ExecutionCount); - - _ = async ? await query.ToListAsync() : query.ToList(); - - AssertNormalOutcome(context, interceptor); - Assert.Equal(2, interceptor.ExecutionCount); - } - - protected class QueryCompilationDelegateChangingInterceptor : TestQueryExpressionInterceptor - { - public int ExecutionCount { get; set; } - - public override Func CompiledQuery( - Expression queryExpression, - QueryExpressionEventData eventData, - Func queryExecutor) - => base.CompiledQuery( - queryExpression, eventData, queryContext => - { - ExecutionCount++; - return queryExecutor(queryContext); - }); - } - protected static void AssertNormalOutcome(DbContext context,TestQueryExpressionInterceptor interceptor) { Assert.Same(context, interceptor.Context); - Assert.True(interceptor.ProcessingQueryCalled); - Assert.True(interceptor.ProcessingQueryCalled); - Assert.True(interceptor.CompilingQueryCalled); - Assert.True(interceptor.CompiledQueryCalled); + Assert.True(interceptor.QueryCompilationStartingCalled); + Assert.True(interceptor.QueryCompilationStartingCalled); } protected class TestQueryExpressionInterceptor : IQueryExpressionInterceptor { - public bool ProcessingQueryCalled { get; set; } - public bool CompilingQueryCalled { get; set; } - public bool CompiledQueryCalled { get; set; } + public bool QueryCompilationStartingCalled { get; set; } public string QueryExpression { get; set; } public DbContext Context { get; set; } - public virtual Expression ProcessingQuery( + public virtual Expression QueryCompilationStarting( Expression queryExpression, QueryExpressionEventData eventData) { - ProcessingQueryCalled = true; + QueryCompilationStartingCalled = true; Context = eventData.Context; QueryExpression = eventData.ExpressionPrinter.Print(queryExpression); return queryExpression; } - - public virtual Expression> CompilingQuery( - Expression queryExpression, - Expression> queryExecutorExpression, - QueryExpressionEventData eventData) - { - CompilingQueryCalled = true; - Assert.Equal(QueryExpression, eventData.ExpressionPrinter.Print(queryExpression)); - Assert.Same(Context, eventData.Context); - - return queryExecutorExpression; - } - - public virtual Func CompiledQuery( - Expression queryExpression, - QueryExpressionEventData eventData, - Func queryExecutor) - { - CompiledQueryCalled = true; - Assert.Equal(QueryExpression, eventData.ExpressionPrinter.Print(queryExpression)); - Assert.Same(Context, eventData.Context); - - return queryExecutor; - } } } diff --git a/test/EFCore.Tests/ChangeTracking/Internal/FixupTest.cs b/test/EFCore.Tests/ChangeTracking/Internal/FixupTest.cs index e6a8154411b..d7b94f4ddb0 100644 --- a/test/EFCore.Tests/ChangeTracking/Internal/FixupTest.cs +++ b/test/EFCore.Tests/ChangeTracking/Internal/FixupTest.cs @@ -2237,7 +2237,7 @@ public void Attaching_dependent_with_duplicate_principal_resolves(bool copy, boo using var context = new FixupContext( copy ? new UpdatingIdentityResolutionInterceptor(preserveModified, updateOriginal) - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var originalCategory = new Category(1) { Value1 = "Original", Value2 = "Original"}; var originalProduct = new Product(1, 0) { Value1 = "Original", Value2 = "Original"}; @@ -2296,7 +2296,7 @@ public void Attaching_duplicate_dependent_with_duplicate_principal_resolves(bool using var context = new FixupContext( copy ? new UpdatingIdentityResolutionInterceptor(preserveModified, updateOriginal) - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var originalCategory = new Category(1) { Value1 = "Original", Value2 = "Original" }; var originalProduct = new Product(1, 0) { Value1 = "Original", Value2 = "Original" }; @@ -2348,7 +2348,7 @@ public void Attaching_principal_with_duplicate_dependent_resolves(bool copy, boo using var context = new FixupContext( copy ? new UpdatingIdentityResolutionInterceptor(preserveModified, updateOriginal) - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var originalCategory = new Category(1) { Value1 = "Original", Value2 = "Original" }; var originalProduct = new Product(1, 0) { Value1 = "Original", Value2 = "Original" }; @@ -2413,7 +2413,7 @@ public void Attaching_duplicate_principal_with_duplicate_dependent_resolves(bool using var context = new FixupContext( copy ? new UpdatingIdentityResolutionInterceptor(preserveModified, updateOriginal) - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var originalCategory = new Category(1) { Value1 = "Original", Value2 = "Original" }; var originalProduct = new Product(1, 0) { Value1 = "Original", Value2 = "Original" }; @@ -2465,7 +2465,7 @@ public void Attaching_one_to_one_dependent_with_duplicate_principal_resolves(boo using var context = new FixupContext( copy ? new UpdatingIdentityResolutionInterceptor(preserveModified, updateOriginal) - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var originalParent = new Parent(1) { Value1 = "Original", Value2 = "Original" }; var originalChild = new Child(1, 0) { Value1 = "Original", Value2 = "Original" }; @@ -2519,7 +2519,7 @@ public void Attaching_one_to_one_duplicate_dependent_with_duplicate_principal_re using var context = new FixupContext( copy ? new UpdatingIdentityResolutionInterceptor(preserveModified, updateOriginal) - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var originalParent = new Parent(1) { Value1 = "Original", Value2 = "Original" }; var originalChild = new Child(1, 0) { Value1 = "Original", Value2 = "Original" }; @@ -2570,7 +2570,7 @@ public void Attaching_one_to_one_principal_with_duplicate_dependent_resolves(boo using var context = new FixupContext( copy ? new UpdatingIdentityResolutionInterceptor(preserveModified, updateOriginal) - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var originalParent = new Parent(1) { Value1 = "Original", Value2 = "Original" }; var originalChild = new Child(1, 0) { Value1 = "Original", Value2 = "Original" }; @@ -2626,7 +2626,7 @@ public void Attaching_one_to_one_duplicate_principal_with_duplicate_dependent_re using var context = new FixupContext( copy ? new UpdatingIdentityResolutionInterceptor(preserveModified, updateOriginal) - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var originalParent = new Parent(1) { Value1 = "Original", Value2 = "Original" }; var originalChild = new Child(1, 0) { Value1 = "Original", Value2 = "Original" }; @@ -2683,7 +2683,7 @@ public void Attaching_entity_with_duplicate_many_to_many_resolves( using var context = new FixupContext( copy ? new UpdatingIdentityResolutionInterceptor(preserveModified, updateOriginal) - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var originalHumans = new Human[] { @@ -3252,7 +3252,7 @@ public async Task Detached_entity_can_be_replaced_by_tracked_entity(bool async, using var context = new BadBeeContext( nameof(BadBeeContext), copy ? new UpdatingIdentityResolutionInterceptor() - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var b1 = new EntityB { EntityBId = 1, Value = "b1" }; context.BEntities.Attach(b1); diff --git a/test/EFCore.Tests/ChangeTracking/Internal/StateManagerTest.cs b/test/EFCore.Tests/ChangeTracking/Internal/StateManagerTest.cs index 4356660d73f..b9b5691970f 100644 --- a/test/EFCore.Tests/ChangeTracking/Internal/StateManagerTest.cs +++ b/test/EFCore.Tests/ChangeTracking/Internal/StateManagerTest.cs @@ -48,7 +48,7 @@ public void Identity_conflict_can_be_resolved(bool copy) { using var context = new IdentityConflictContext(copy ? new UpdatingIdentityResolutionInterceptor() - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var entity = new SingleKey { Id = 77, AlternateId = 66, Value = "Existing" }; context.Attach(entity); @@ -76,7 +76,7 @@ public void Resolving_identity_conflict_for_primary_key_cannot_change_alternate_ [ConditionalFact] public void Resolving_identity_conflict_for_primary_key_throws_if_alternate_key_changes() { - using var context = new IdentityConflictContext(new SkippingIdentityResolutionInterceptor()); + using var context = new IdentityConflictContext(new IgnoringIdentityResolutionInterceptor()); context.Attach(new SingleKey { Id = 77, AlternateId = 66 }); @@ -116,16 +116,16 @@ public void Resolving_identity_conflict_for_alternate_key_cannot_change_primary_ private class NaiveCopyingIdentityResolutionInterceptor : IIdentityResolutionInterceptor { - public void UpdateTrackedInstance(DbContext context, EntityEntry existingEntry, object newInstance) + public void UpdateTrackedInstance(IdentityResolutionInterceptionData interceptionData, EntityEntry existingEntry, object newEntity) { - existingEntry.CurrentValues.SetValues(newInstance); + existingEntry.CurrentValues.SetValues(newEntity); } } [ConditionalFact] public void Resolving_identity_conflict_for_alternate_key_throws_if_primary_key_changes() { - using var context = new IdentityConflictContext(new SkippingIdentityResolutionInterceptor()); + using var context = new IdentityConflictContext(new IgnoringIdentityResolutionInterceptor()); context.Attach(new SingleKey { Id = 77, AlternateId = 66 }); Assert.Equal( @@ -169,7 +169,7 @@ public void Identity_conflict_can_be_resolved_for_owned(bool copy) { using var context = new IdentityConflictContext(copy ? new UpdatingIdentityResolutionInterceptor() - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var owned = new SingleKeyOwned { Value = "Existing" }; context.Attach( @@ -229,7 +229,7 @@ public void Identity_conflict_can_be_resolved_for_composite_primary_key(bool cop { using var context = new IdentityConflictContext(copy ? new UpdatingIdentityResolutionInterceptor() - : new SkippingIdentityResolutionInterceptor()); + : new IgnoringIdentityResolutionInterceptor()); var entity = new CompositeKey { diff --git a/test/EFCore.Tests/Metadata/Conventions/IndexAttributeConventionTest.cs b/test/EFCore.Tests/Metadata/Conventions/IndexAttributeConventionTest.cs index e989e1dfc84..8b7d62bcb5c 100644 --- a/test/EFCore.Tests/Metadata/Conventions/IndexAttributeConventionTest.cs +++ b/test/EFCore.Tests/Metadata/Conventions/IndexAttributeConventionTest.cs @@ -92,7 +92,7 @@ public void IndexAttribute_properties_cannot_include_whitespace(Type entityTypeW var modelBuilder = InMemoryTestHelpers.Instance.CreateConventionBuilder(); Assert.Equal( - AbstractionsStrings.CollectionArgumentHasEmptyElements("propertyNames"), + AbstractionsStrings.CollectionArgumentHasEmptyElements("additionalPropertyNames"), Assert.Throws( () => modelBuilder.Entity(entityTypeWithInvalidIndex)).Message); } @@ -356,7 +356,9 @@ private class EntityWithIndexFromBaseType : BaseUnmappedEntityWithIndex public int D { get; set; } } +#pragma warning disable CS0618 [Index] +#pragma warning restore CS0618 private class EntityWithInvalidEmptyIndex { public int Id { get; set; } @@ -364,7 +366,7 @@ private class EntityWithInvalidEmptyIndex public int B { get; set; } } - [Index(nameof(A), null, Name = "IndexOnAAndNull")] + [Index(nameof(A), (string)null, Name = "IndexOnAAndNull")] private class EntityWithInvalidNullIndexProperty { public int Id { get; set; }