Skip to content

Commit

Permalink
Snapshot events.
Browse files Browse the repository at this point in the history
Fixes #27473.
  • Loading branch information
ajcvickers committed Jun 29, 2022
1 parent 1f18dd1 commit a1ecd0f
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 60 deletions.
26 changes: 25 additions & 1 deletion src/EFCore/ChangeTracking/Internal/ChangeDetector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,31 @@ public bool DetectNavigationChange(InternalEntityEntry entry, INavigationBase na

return false;
}


/// <summary>
/// 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.
/// </summary>
public virtual (EventHandler<DetectChangesEventArgs>? DetectingChanges,
EventHandler<DetectedChangesEventArgs>? DetectedChanges) CaptureEvents()
=> (DetectingChanges, DetectedChanges);

/// <summary>
/// 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.
/// </summary>
public virtual void SetEvents(
EventHandler<DetectChangesEventArgs>? detectingChanges,
EventHandler<DetectedChangesEventArgs>? detectedChanges)
{
DetectingChanges = detectingChanges;
DetectedChanges = detectedChanges;
}

/// <summary>
/// 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
Expand Down
19 changes: 19 additions & 0 deletions src/EFCore/ChangeTracking/Internal/IChangeDetector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,25 @@ public interface IChangeDetector
/// </summary>
void DetectChanges(InternalEntityEntry entry);

/// <summary>
/// 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.
/// </summary>
(EventHandler<DetectChangesEventArgs>? DetectingChanges,
EventHandler<DetectedChangesEventArgs>? DetectedChanges) CaptureEvents();

/// <summary>
/// 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.
/// </summary>
void SetEvents(
EventHandler<DetectChangesEventArgs>? detectingChanges,
EventHandler<DetectedChangesEventArgs>? detectedChanges);

/// <summary>
/// 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
Expand Down
23 changes: 23 additions & 0 deletions src/EFCore/ChangeTracking/Internal/IStateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,29 @@ IEnumerable<IUpdateEntry> GetDependentsUsingRelationshipSnapshot(
/// </summary>
void Unsubscribe();

/// <summary>
/// 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.
/// </summary>
(EventHandler<EntityTrackingEventArgs>? Tracking,
EventHandler<EntityTrackedEventArgs>? Tracked,
EventHandler<EntityStateChangingEventArgs>? StateChanging,
EventHandler<EntityStateChangedEventArgs>? StateChanged) CaptureEvents();

/// <summary>
/// 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.
/// </summary>
void SetEvents(
EventHandler<EntityTrackingEventArgs>? tracking,
EventHandler<EntityTrackedEventArgs>? tracked,
EventHandler<EntityStateChangingEventArgs>? stateChanging,
EventHandler<EntityStateChangedEventArgs>? stateChanged);

/// <summary>
/// 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
Expand Down
31 changes: 31 additions & 0 deletions src/EFCore/ChangeTracking/Internal/StateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,37 @@ private static void AcceptAllChanges(IReadOnlyList<IUpdateEntry> changedEntries)
}
}

/// <summary>
/// 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.
/// </summary>
public virtual (
EventHandler<EntityTrackingEventArgs>? Tracking,
EventHandler<EntityTrackedEventArgs>? Tracked,
EventHandler<EntityStateChangingEventArgs>? StateChanging,
EventHandler<EntityStateChangedEventArgs>? StateChanged) CaptureEvents()
=> (Tracking, Tracked, StateChanging, StateChanged);

/// <summary>
/// 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.
/// </summary>
public virtual void SetEvents(
EventHandler<EntityTrackingEventArgs>? tracking,
EventHandler<EntityTrackedEventArgs>? tracked,
EventHandler<EntityStateChangingEventArgs>? stateChanging,
EventHandler<EntityStateChangedEventArgs>? stateChanged)
{
Tracking = tracking;
Tracked = tracked;
StateChanging = stateChanging;
StateChanged = stateChanged;
}

/// <summary>
/// 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
Expand Down
75 changes: 56 additions & 19 deletions src/EFCore/DbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -854,16 +854,42 @@ private void SetLeaseInternal(DbContextLease lease)

Check.DebugAssert(_configurationSnapshot != null, "configurationSnapshot is null");

var changeTracker = ChangeTracker;
changeTracker.AutoDetectChangesEnabled = _configurationSnapshot.AutoDetectChangesEnabled;
changeTracker.QueryTrackingBehavior = _configurationSnapshot.QueryTrackingBehavior;
changeTracker.LazyLoadingEnabled = _configurationSnapshot.LazyLoadingEnabled;
changeTracker.CascadeDeleteTiming = _configurationSnapshot.CascadeDeleteTiming;
changeTracker.DeleteOrphansTiming = _configurationSnapshot.DeleteOrphansTiming;
if (_changeTracker != null
|| _configurationSnapshot.HasChangeTrackerConfiguration)
{
var changeTracker = ChangeTracker;
changeTracker.AutoDetectChangesEnabled = _configurationSnapshot.AutoDetectChangesEnabled;
changeTracker.QueryTrackingBehavior = _configurationSnapshot.QueryTrackingBehavior;
changeTracker.LazyLoadingEnabled = _configurationSnapshot.LazyLoadingEnabled;
changeTracker.CascadeDeleteTiming = _configurationSnapshot.CascadeDeleteTiming;
changeTracker.DeleteOrphansTiming = _configurationSnapshot.DeleteOrphansTiming;
}

if (_database != null
|| _configurationSnapshot.HasDatabaseConfiguration)
{
var database = Database;
database.AutoTransactionsEnabled = _configurationSnapshot.AutoTransactionsEnabled;
database.AutoSavepointsEnabled = _configurationSnapshot.AutoSavepointsEnabled;
}

var database = Database;
database.AutoTransactionsEnabled = _configurationSnapshot.AutoTransactionsEnabled;
database.AutoSavepointsEnabled = _configurationSnapshot.AutoSavepointsEnabled;
if (_dbContextDependencies != null
|| _configurationSnapshot.HasStateManagerConfiguration)
{
DbContextDependencies.StateManager.SetEvents(
_configurationSnapshot.Tracking,
_configurationSnapshot.Tracked,
_configurationSnapshot.StateChanging,
_configurationSnapshot.StateChanged);
}

if (_dbContextDependencies != null
|| _configurationSnapshot.HasChangeDetectorConfiguration)
{
DbContextDependencies.ChangeDetector.SetEvents(
_configurationSnapshot.DetectingChanges,
_configurationSnapshot.DetectedChanges);
}

SavingChanges = _configurationSnapshot.SavingChanges;
SavedChanges = _configurationSnapshot.SavedChanges;
Expand All @@ -879,19 +905,30 @@ private void SetLeaseInternal(DbContextLease lease)
[EntityFrameworkInternal]
void IDbContextPoolable.SnapshotConfiguration()
{
var changeTracker = ChangeTracker;
var database = Database;
var stateManagerEvents = _dbContextDependencies?.StateManager.CaptureEvents();
var changeDetectorEvents = _dbContextDependencies?.ChangeDetector.CaptureEvents();

_configurationSnapshot = new DbContextPoolConfigurationSnapshot(
changeTracker.AutoDetectChangesEnabled,
changeTracker.QueryTrackingBehavior,
database.AutoTransactionsEnabled,
database.AutoSavepointsEnabled,
changeTracker.LazyLoadingEnabled,
changeTracker.CascadeDeleteTiming,
changeTracker.DeleteOrphansTiming,
_database != null,
stateManagerEvents != null,
_changeTracker != null,
changeDetectorEvents != null,
_changeTracker?.AutoDetectChangesEnabled ?? true,
_changeTracker?.QueryTrackingBehavior ?? QueryTrackingBehavior.TrackAll,
_database?.AutoTransactionsEnabled ?? true,
_database?.AutoSavepointsEnabled ?? true,
_changeTracker?.LazyLoadingEnabled ?? true,
_changeTracker?.CascadeDeleteTiming ?? CascadeTiming.Immediate,
_changeTracker?.DeleteOrphansTiming ?? CascadeTiming.Immediate,
SavingChanges,
SavedChanges,
SaveChangesFailed);
SaveChangesFailed,
stateManagerEvents?.Tracking,
stateManagerEvents?.Tracked,
stateManagerEvents?.StateChanging,
stateManagerEvents?.StateChanged,
changeDetectorEvents?.DetectingChanges,
changeDetectorEvents?.DetectedChanges);
}

/// <summary>
Expand Down
102 changes: 101 additions & 1 deletion src/EFCore/Internal/DbContextPoolConfigurationSnapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ public sealed class DbContextPoolConfigurationSnapshot
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public DbContextPoolConfigurationSnapshot(
bool hasDatabaseConfiguration,
bool hasStateManagerConfiguration,
bool hasChangeTrackerConfiguration,
bool hasChangeDetectorConfiguration,
bool autoDetectChangesEnabled,
QueryTrackingBehavior queryTrackingBehavior,
bool autoTransactionsEnabled,
Expand All @@ -27,8 +31,18 @@ public DbContextPoolConfigurationSnapshot(
CascadeTiming deleteOrphansTiming,
EventHandler<SavingChangesEventArgs>? savingChanges,
EventHandler<SavedChangesEventArgs>? savedChanges,
EventHandler<SaveChangesFailedEventArgs>? saveChangesFailed)
EventHandler<SaveChangesFailedEventArgs>? saveChangesFailed,
EventHandler<EntityTrackingEventArgs>? tracking,
EventHandler<EntityTrackedEventArgs>? tracked,
EventHandler<EntityStateChangingEventArgs>? stateChanging,
EventHandler<EntityStateChangedEventArgs>? stateChanged,
EventHandler<DetectChangesEventArgs>? detectingChanges,
EventHandler<DetectedChangesEventArgs>? detectedChanges)
{
HasDatabaseConfiguration = hasDatabaseConfiguration;
HasStateManagerConfiguration = hasStateManagerConfiguration;
HasChangeTrackerConfiguration = hasChangeTrackerConfiguration;
HasChangeDetectorConfiguration = hasChangeDetectorConfiguration;
AutoDetectChangesEnabled = autoDetectChangesEnabled;
QueryTrackingBehavior = queryTrackingBehavior;
AutoTransactionsEnabled = autoTransactionsEnabled;
Expand All @@ -39,8 +53,46 @@ public DbContextPoolConfigurationSnapshot(
SavingChanges = savingChanges;
SavedChanges = savedChanges;
SaveChangesFailed = saveChangesFailed;
Tracking = tracking;
Tracked = tracked;
StateChanging = stateChanging;
StateChanged = stateChanged;
DetectingChanges = detectingChanges;
DetectedChanges = detectedChanges;
}

/// <summary>
/// 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.
/// </summary>
public bool HasDatabaseConfiguration { get; }

/// <summary>
/// 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.
/// </summary>
public bool HasStateManagerConfiguration { get; }

/// <summary>
/// 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.
/// </summary>
public bool HasChangeTrackerConfiguration { get; }

/// <summary>
/// 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.
/// </summary>
public bool HasChangeDetectorConfiguration { get; }

/// <summary>
/// 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
Expand Down Expand Up @@ -120,4 +172,52 @@ public DbContextPoolConfigurationSnapshot(
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public EventHandler<SaveChangesFailedEventArgs>? SaveChangesFailed { get; }

/// <summary>
/// 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.
/// </summary>
public EventHandler<EntityTrackingEventArgs>? Tracking { get; }

/// <summary>
/// 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.
/// </summary>
public EventHandler<EntityTrackedEventArgs>? Tracked { get; }

/// <summary>
/// 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.
/// </summary>
public EventHandler<EntityStateChangingEventArgs>? StateChanging { get; }

/// <summary>
/// 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.
/// </summary>
public EventHandler<EntityStateChangedEventArgs>? StateChanged { get; }

/// <summary>
/// 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.
/// </summary>
public EventHandler<DetectChangesEventArgs>? DetectingChanges { get; }

/// <summary>
/// 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.
/// </summary>
public EventHandler<DetectedChangesEventArgs>? DetectedChanges { get; }
}
Loading

0 comments on commit a1ecd0f

Please sign in to comment.