We have a general item to add better lifecycle hooks to DbContext--see http://entityframework.codeplex.com/workitem/872
However, this doesn't fit in the schedule for EF6, so this work item is about adding specific hooks for getting SQL generated by EF without having to create a wrapping provider. This is for both queries and CRUD operations.
The probable approach for this will be to add one or more low-level interception services that can be registered via DbConfiguration.
Comments: First checkin on this: 1adce0b65e3c EveryStepYouTake... (Building blocks for interception) These changes build on the work previously done to add the building blocks for interception and provide concrete implementations of these for DbCommand execution interception. The basic parts are: - A set of interfaces that provide the interception methods for types/operations that can be intercepted. Currently public interfaces are provided for command execution and command tree creation, and there are also two internal interfaces used by Code First/Migrations. - A mechanism for registering objects that implement one or more interception interfaces. - A mechanism for dispatching notifications to the registered interfaces. This mechanism is public so that external code (such as providers) can dispatch notifications when doing things on behalf of EF. Currently only dispatching for command execution is public. - The mechanism for registering/dispatching is intended to be optimized for fast dispatch rather than fast registration. Also, registering an interceptor for one interface does not slow down execution/dispatch around other interfaces. - A mechanism to provide contextual information about the operation to the interceptors. Currently this contextual information contains the ObjectContext/DbContexts that cause the operation to happen (when available) but in the future we can include other information here--for example, we may include the public surface method (e.g. SaveChanges) that triggered the operation. - Interceptors can be flexible in how the callback methods are defined. Currently the command execution interceptor interface has methods for before and after execution with the result of the execution supplied to the “after” methods. The “after” methods can also modify the result before returning it. There is an internal command dispatcher that allows cancellations, but the publicly exposed version does not since cancellation needs to be handled properly at all call sites. Open questions/remaining work includes: - We should define a nice sugar API on the context for logging SQL. We need to decide what this looks like, what it supports, and what the consequences are for trace strings and parameters. - Interceptors could be defined for many more things. We should decide which others (if any) we want to do and have time to do for EF6. For example, DbProviderServices, DbConnection, other DbCommand operations, transactions, etc. - Is the granularity of the interception methods correct, especially for command interception? For example, should we collapse the sync and async methods? (This has consequences for handling results.) - What should happen if the operation that is being intercepted throws? Should the “after” method be called? (Currently it isn’t.) If it should be called, should it contain exception information? - These are very low level interceptions. We currently call them the way we do. In the future we may change internal code so that we call them differently. Should we be concerned about the potential for breaking changes here? - The command tree interception context contains the ObejctContext/DbContext when one is available. However, command trees can be cached, which means sometimes a context will “see” a command tree created and sometimes it will not. Is this an issue? - Is it okay, from a perf perspective, for all interceptors of a certain type to be globally registered? - Is it okay for the command execution Dispatch methods to also actually execute the command? This makes using the dispatcher super-easy and ensures before and after methods are always called, but in a sense dispatching to interceptors and actually execution could be considered separate concerns. - Should command tree dispatch also be public? In general, if we have public interceptors for something, should that thing also be publicly dispatchable? - Are there other things we should put in the interception context for EF6?
However, this doesn't fit in the schedule for EF6, so this work item is about adding specific hooks for getting SQL generated by EF without having to create a wrapping provider. This is for both queries and CRUD operations.
The probable approach for this will be to add one or more low-level interception services that can be registered via DbConfiguration.
Comments: First checkin on this: 1adce0b65e3c EveryStepYouTake... (Building blocks for interception) These changes build on the work previously done to add the building blocks for interception and provide concrete implementations of these for DbCommand execution interception. The basic parts are: - A set of interfaces that provide the interception methods for types/operations that can be intercepted. Currently public interfaces are provided for command execution and command tree creation, and there are also two internal interfaces used by Code First/Migrations. - A mechanism for registering objects that implement one or more interception interfaces. - A mechanism for dispatching notifications to the registered interfaces. This mechanism is public so that external code (such as providers) can dispatch notifications when doing things on behalf of EF. Currently only dispatching for command execution is public. - The mechanism for registering/dispatching is intended to be optimized for fast dispatch rather than fast registration. Also, registering an interceptor for one interface does not slow down execution/dispatch around other interfaces. - A mechanism to provide contextual information about the operation to the interceptors. Currently this contextual information contains the ObjectContext/DbContexts that cause the operation to happen (when available) but in the future we can include other information here--for example, we may include the public surface method (e.g. SaveChanges) that triggered the operation. - Interceptors can be flexible in how the callback methods are defined. Currently the command execution interceptor interface has methods for before and after execution with the result of the execution supplied to the “after” methods. The “after” methods can also modify the result before returning it. There is an internal command dispatcher that allows cancellations, but the publicly exposed version does not since cancellation needs to be handled properly at all call sites. Open questions/remaining work includes: - We should define a nice sugar API on the context for logging SQL. We need to decide what this looks like, what it supports, and what the consequences are for trace strings and parameters. - Interceptors could be defined for many more things. We should decide which others (if any) we want to do and have time to do for EF6. For example, DbProviderServices, DbConnection, other DbCommand operations, transactions, etc. - Is the granularity of the interception methods correct, especially for command interception? For example, should we collapse the sync and async methods? (This has consequences for handling results.) - What should happen if the operation that is being intercepted throws? Should the “after” method be called? (Currently it isn’t.) If it should be called, should it contain exception information? - These are very low level interceptions. We currently call them the way we do. In the future we may change internal code so that we call them differently. Should we be concerned about the potential for breaking changes here? - The command tree interception context contains the ObejctContext/DbContext when one is available. However, command trees can be cached, which means sometimes a context will “see” a command tree created and sometimes it will not. Is this an issue? - Is it okay, from a perf perspective, for all interceptors of a certain type to be globally registered? - Is it okay for the command execution Dispatch methods to also actually execute the command? This makes using the dispatcher super-easy and ensures before and after methods are always called, but in a sense dispatching to interceptors and actually execution could be considered separate concerns. - Should command tree dispatch also be public? In general, if we have public interceptors for something, should that thing also be publicly dispatchable? - Are there other things we should put in the interception context for EF6?