Skip to content

Commit

Permalink
API review bundle (#28504)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajcvickers authored Jul 26, 2022
1 parent 390318f commit 024fd3b
Show file tree
Hide file tree
Showing 24 changed files with 189 additions and 309 deletions.
15 changes: 15 additions & 0 deletions src/EFCore.Abstractions/IndexAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,25 @@ public sealed class IndexAttribute : Attribute
private bool? _isUnique;
private bool[]? _isDescending;

/// <summary>
/// Initializes a new instance of the <see cref="IndexAttribute" /> class.
/// </summary>
/// <param name="propertyName">The first (or only) property in the index.</param>
/// <param name="additionalPropertyNames">The additional properties which constitute the index, if any, in order.</param>
public IndexAttribute(string propertyName, params string[] additionalPropertyNames)
{
Check.NotEmpty(propertyName, nameof(propertyName));
Check.HasNoEmptyElements(additionalPropertyNames, nameof(additionalPropertyNames));

PropertyNames = new List<string> { propertyName };
((List<string>)PropertyNames).AddRange(additionalPropertyNames);
}

/// <summary>
/// Initializes a new instance of the <see cref="IndexAttribute" /> class.
/// </summary>
/// <param name="propertyNames">The properties which constitute the index, in order (there must be at least one).</param>
[Obsolete("Use the other constructor")]
public IndexAttribute(params string[] propertyNames)
{
Check.NotEmpty(propertyNames, nameof(propertyNames));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/// </summary>
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)
Expand Down
3 changes: 2 additions & 1 deletion src/EFCore/ChangeTracking/Internal/StateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -781,14 +781,15 @@ public virtual bool ResolveToExistingEntry(
{
if (_resolutionInterceptor != null)
{
var interceptionData = new IdentityResolutionInterceptionData(Context);
var needsTracking = false;
foreach (var key in newEntry.EntityType.GetKeys())
{
var existingEntry = FindIdentityMap(key)?.TryGetEntry(newEntry);
if (existingEntry != null)
{
_resolutionInterceptor.UpdateTrackedInstance(
Context,
interceptionData,
new EntityEntry(existingEntry),
newEntry.Entity);

Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/Diagnostics/CoreLoggerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/EFCore/Diagnostics/IIdentityResolutionInterceptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/// </summary>
/// <param name="context">The <see cref="DbContext"/> is use.</param>
/// <param name="interceptionData">Contextual information about the identity resolution.</param>
/// <param name="existingEntry">The entry for the existing tracked entity instance.</param>
/// <param name="newInstance">The new entity instance, which will be discarded after this call.</param>
void UpdateTrackedInstance(DbContext context, EntityEntry existingEntry, object newInstance);
/// <param name="newEntity">The new entity instance, which will be discarded after this call.</param>
void UpdateTrackedInstance(IdentityResolutionInterceptionData interceptionData, EntityEntry existingEntry, object newEntity);
}
5 changes: 2 additions & 3 deletions src/EFCore/Diagnostics/IInstantiationBindingInterceptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ public interface IInstantiationBindingInterceptor : ISingletonInterceptor
/// <summary>
/// Returns a new <see cref="InstantiationBinding" /> for the given entity type, potentially modified from the given binding.
/// </summary>
/// <param name="entityType">The entity type for which the binding is being used.</param>
/// <param name="entityInstanceName">The name of the instance being materialized.</param>
/// <param name="interceptionData">Contextual information about the binding.</param>
/// <param name="binding">The current binding.</param>
/// <returns>A new binding.</returns>
InstantiationBinding ModifyBinding(IEntityType entityType, string entityInstanceName, InstantiationBinding binding);
InstantiationBinding ModifyBinding(InstantiationBindingInterceptionData interceptionData, InstantiationBinding binding);
}
20 changes: 10 additions & 10 deletions src/EFCore/Diagnostics/IMaterializationInterceptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,24 @@ InterceptionResult<object> CreatingInstance(MaterializationInterceptionData mate
/// any properties values not set by the constructor have been set.
/// </summary>
/// <param name="materializationData">Contextual information about the materialization happening.</param>
/// <param name="instance">
/// <param name="entity">
/// The entity instance that has been created.
/// This value is typically used as the return value for the implementation of this method.
/// </param>
/// <returns>
/// 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 <paramref name="instance" /> value passed in.
/// must return the <paramref name="entity" /> value passed in.
/// </returns>
object CreatedInstance(MaterializationInterceptionData materializationData, object instance)
=> instance;
object CreatedInstance(MaterializationInterceptionData materializationData, object entity)
=> entity;

/// <summary>
/// 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.
/// </summary>
/// <param name="materializationData">Contextual information about the materialization happening.</param>
/// <param name="instance">The entity instance for which property values will be set.</param>
/// <param name="entity">The entity instance for which property values will be set.</param>
/// <param name="result">
/// Represents the current result if one exists.
/// This value will have <see cref="InterceptionResult.IsSuppressed" /> set to <see langword="true" /> if some previous
Expand All @@ -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 <paramref name="result" /> value passed in.
/// </returns>
InterceptionResult InitializingInstance(MaterializationInterceptionData materializationData, object instance, InterceptionResult result)
InterceptionResult InitializingInstance(MaterializationInterceptionData materializationData, object entity, InterceptionResult result)
=> result;

/// <summary>
/// Called immediately after EF has set property values of an entity that has just been created.
/// </summary>
/// <param name="materializationData">Contextual information about the materialization happening.</param>
/// <param name="instance">
/// <param name="entity">
/// The entity instance that has been created.
/// This value is typically used as the return value for the implementation of this method.
/// </param>
/// <returns>
/// 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 <paramref name="instance" /> value passed in.
/// must return the <paramref name="entity" /> value passed in.
/// </returns>
object InitializedInstance(MaterializationInterceptionData materializationData, object instance)
=> instance;
object InitializedInstance(MaterializationInterceptionData materializationData, object entity)
=> entity;
}
30 changes: 1 addition & 29 deletions src/EFCore/Diagnostics/IQueryExpressionInterceptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,36 +28,8 @@ public interface IQueryExpressionInterceptor : IInterceptor
/// <param name="queryExpression">The query expression.</param>
/// <param name="eventData">Contextual information about the query environment.</param>
/// <returns>The query expression tree to continue with, which may have been changed by the interceptor.</returns>
Expression ProcessingQuery(
Expression QueryCompilationStarting(
Expression queryExpression,
QueryExpressionEventData eventData)
=> queryExpression;

/// <summary>
/// Called when EF is about to compile the query delegate that will be used to execute the query.
/// </summary>
/// <param name="queryExpression">The query expression.</param>
/// <param name="queryExecutorExpression">The expression that will be compiled into the execution delegate.</param>
/// <param name="eventData">Contextual information about the query environment.</param>
/// <typeparam name="TResult">The return type of the execution delegate.</typeparam>
/// <returns>The expression that will be compiled into the execution delegate, which may have been changed by the interceptor.</returns>
Expression<Func<QueryContext, TResult>> CompilingQuery<TResult>(
Expression queryExpression,
Expression<Func<QueryContext, TResult>> queryExecutorExpression,
QueryExpressionEventData eventData)
=> queryExecutorExpression;

/// <summary>
/// Called when EF is about to compile the query delegate that will be used to execute the query.
/// </summary>
/// <param name="queryExpression">The query expression.</param>
/// <param name="eventData">Contextual information about the query environment.</param>
/// <param name="queryExecutor">The delegate that will be used to execute the query.</param>
/// <typeparam name="TResult">The return type of the execution delegate.</typeparam>
/// <returns>The delegate that will be used to execute the query, which may have been changed by the interceptor.</returns>
Func<QueryContext, TResult> CompiledQuery<TResult>(
Expression queryExpression,
QueryExpressionEventData eventData,
Func<QueryContext, TResult> queryExecutor)
=> queryExecutor;
}
27 changes: 27 additions & 0 deletions src/EFCore/Diagnostics/IdentityResolutionInterceptionData.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// A parameter object passed to <see cref="IIdentityResolutionInterceptor" /> methods.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-diagnostics">Logging, events, and diagnostics</see> for more information and examples.
/// </remarks>
public readonly struct IdentityResolutionInterceptionData
{
/// <summary>
/// Constructs the parameter object.
/// </summary>
/// <param name="context">The <see cref="DbContext"/> in use.</param>
public IdentityResolutionInterceptionData(DbContext context)
{
Context = context;
}

/// <summary>
/// The current <see cref="DbContext" /> instance being used.
/// </summary>
public DbContext Context { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ namespace Microsoft.EntityFrameworkCore.Diagnostics;
/// A <see cref="IIdentityResolutionInterceptor"/> that ignores the new instance and retains property values from the existing
/// tracked instance.
/// </summary>
public class SkippingIdentityResolutionInterceptor : IIdentityResolutionInterceptor
public class IgnoringIdentityResolutionInterceptor : IIdentityResolutionInterceptor
{
/// <summary>
/// Called when a <see cref="DbContext"/> 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.
/// </summary>
/// <param name="context">The <see cref="DbContext"/> is use.</param>
/// <param name="interceptionData">Contextual information about the identity resolution.</param>
/// <param name="existingEntry">The entry for the existing tracked entity instance.</param>
/// <param name="newInstance">The new entity instance, which will be discarded after this call.</param>
public virtual void UpdateTrackedInstance(DbContext context, EntityEntry existingEntry, object newInstance)
/// <param name="newEntity">The new entity instance, which will be discarded after this call.</param>
public virtual void UpdateTrackedInstance(IdentityResolutionInterceptionData interceptionData, EntityEntry existingEntry, object newEntity)
{
}
}
28 changes: 28 additions & 0 deletions src/EFCore/Diagnostics/InstantiationBindingInterceptionData.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// A parameter object passed to <see cref="IInstantiationBindingInterceptor" /> methods.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-diagnostics">Logging, events, and diagnostics</see> for more information and examples.
/// </remarks>
public readonly struct InstantiationBindingInterceptionData
{

/// <summary>
/// Constructs the parameter object.
/// </summary>
/// <param name="entityType">The entity type for which the binding is being used.</param>
public InstantiationBindingInterceptionData(IEntityType entityType)
{
EntityType = entityType;
}

/// <summary>
/// The entity type for which the binding is being used.
/// </summary>
public IEntityType EntityType { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ public CompositeIdentityResolutionInterceptor(IEnumerable<IIdentityResolutionInt
_interceptors = interceptors.ToArray();
}

public void UpdateTrackedInstance(DbContext context, EntityEntry existingEntry, object newInstance)
public void UpdateTrackedInstance(IdentityResolutionInterceptionData interceptionData, EntityEntry existingEntry, object newEntity)
{
for (var i = 0; i < _interceptors.Length; i++)
{
_interceptors[i].UpdateTrackedInstance(context, existingEntry, newInstance);
_interceptors[i].UpdateTrackedInstance(interceptionData, existingEntry, newEntity);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,39 +42,39 @@ public InterceptionResult<object> 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;
}

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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,42 +24,16 @@ public CompositeQueryExpressionInterceptor(IEnumerable<IQueryExpressionIntercept
_interceptors = interceptors.ToArray();
}

public Expression ProcessingQuery(
public Expression QueryCompilationStarting(
Expression queryExpression,
QueryExpressionEventData eventData)
{
for (var i = 0; i < _interceptors.Length; i++)
{
queryExpression = _interceptors[i].ProcessingQuery(queryExpression, eventData);
queryExpression = _interceptors[i].QueryCompilationStarting(queryExpression, eventData);
}

return queryExpression;
}

public Expression<Func<QueryContext, TResult>> CompilingQuery<TResult>(
Expression queryExpression,
Expression<Func<QueryContext, TResult>> queryExecutorExpression,
QueryExpressionEventData eventData)
{
for (var i = 0; i < _interceptors.Length; i++)
{
queryExecutorExpression = _interceptors[i].CompilingQuery(queryExpression, queryExecutorExpression, eventData);
}

return queryExecutorExpression;
}

public Func<QueryContext, TResult> CompiledQuery<TResult>(
Expression queryExpression,
QueryExpressionEventData eventData,
Func<QueryContext, TResult> queryExecutor)
{
for (var i = 0; i < _interceptors.Length; i++)
{
queryExecutor = _interceptors[i].CompiledQuery(queryExpression, eventData, queryExecutor);
}

return queryExecutor;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/// </summary>
/// <param name="context">The <see cref="DbContext" /> is use.</param>
/// <param name="interceptionData">Contextual information about the identity resolution.</param>
/// <param name="existingEntry">The entry for the existing tracked entity instance.</param>
/// <param name="newInstance">The new entity instance, which will be discarded after this call.</param>
public virtual void UpdateTrackedInstance(DbContext context, EntityEntry existingEntry, object newInstance)
/// <param name="newEntity">The new entity instance, which will be discarded after this call.</param>
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)
{
Expand Down
Loading

0 comments on commit 024fd3b

Please sign in to comment.