Exception suggestion
When querying an ObjectContext and the underlying connection is broken, an InvalidOperationException is thrown.
Would be more useful if a dedicated exception type would be thrown. This will allow the handler to recover the connection.
To illustrate my scenario, I'm using one global ObjectContext instance across my application to improve performance.
When my app failes to retrieve data, the connection is marked as Broken. I want to recover it the next time a retrieval is attempted. My only way to do so is to handle this type of exception at the application level using Application.DispatcherUnhandeledException event, but without explicit exception reasoning I have to rely on StackTrace strings, etc.
Answers
First, you have a valid point that it would be good to have a better exception for the cases where the underlying connection is broken. I believe the InvalidOperation exception is actually thrown from the underlying provider, so we would have to catch this exception and check the connection state in order to determine whether to throw a different exception. For cases where the user *isn't* trying to handle the exception, this results in extra overhead (although for an error case, so it might be justified). Arguably, the provider should be throwing a different exception when operations are attempted on a broken connection.
As a work around, in your exception handler could you check the ObjectContext.Connection.ConnectionState of your global connection to determine if it is broken?
All that said, we generally don't recommend sharing a single global ObjectContext for a number of reasons, including threading issues (ObjectContext is not thread-safe), working set (unless you are using NoTracking queries, ObjectContext keeps a reference to each queried object until you release the ObjectContext or call Detach on the referenced objects), and data consistency (as the data in the database evolves over time it can get out of sync with the data in your local objects).
Have you done performance tests to validate that you are getting a significant advantage in re-using a single ObjectContext over creating each use? In order to promote the usage pattern of short-lived ObjectContexts, we've done a fair amount of work to try and make them cheap to (re)create. The two expensive resources an ObjectContext holds are:
Database Connection: Most providers (including SQL Server) support connection pooling in order to enable creating a connection, using it, and closing it w/o creating a new physical connection each time.
Metadata: We added Metadata caching (I believe in Beta 2) for exactly this scenario in order to make ObjectContexts (relatively) cheap to (re)create.
Since this is the recommended usage, I would be very interested in hearing what type of performance improvements you are actually seeing mantaining a global connection.
Thanks,
-Mike
All Replies
First, you have a valid point that it would be good to have a better exception for the cases where the underlying connection is broken. I believe the InvalidOperation exception is actually thrown from the underlying provider, so we would have to catch this exception and check the connection state in order to determine whether to throw a different exception. For cases where the user *isn't* trying to handle the exception, this results in extra overhead (although for an error case, so it might be justified). Arguably, the provider should be throwing a different exception when operations are attempted on a broken connection.
As a work around, in your exception handler could you check the ObjectContext.Connection.ConnectionState of your global connection to determine if it is broken?
All that said, we generally don't recommend sharing a single global ObjectContext for a number of reasons, including threading issues (ObjectContext is not thread-safe), working set (unless you are using NoTracking queries, ObjectContext keeps a reference to each queried object until you release the ObjectContext or call Detach on the referenced objects), and data consistency (as the data in the database evolves over time it can get out of sync with the data in your local objects).
Have you done performance tests to validate that you are getting a significant advantage in re-using a single ObjectContext over creating each use? In order to promote the usage pattern of short-lived ObjectContexts, we've done a fair amount of work to try and make them cheap to (re)create. The two expensive resources an ObjectContext holds are:
Database Connection: Most providers (including SQL Server) support connection pooling in order to enable creating a connection, using it, and closing it w/o creating a new physical connection each time.
Metadata: We added Metadata caching (I believe in Beta 2) for exactly this scenario in order to make ObjectContexts (relatively) cheap to (re)create.
Since this is the recommended usage, I would be very interested in hearing what type of performance improvements you are actually seeing mantaining a global connection.
Thanks,
-Mike
Michael Pizzo - MSFT wrote: I believe the InvalidOperation exception is actually thrown from the underlying provider..
Using Reflector, you can see that this assumtion is incorrect. The exception is thrown from ObjectContext.
Michael Pizzo - MSFT wrote: As a work around, in your exception handler could you check the ObjectContext.Connection.ConnectionState of your global connection to determine if it is broken?
This is actually what I'm doing. However, it's a partial solution, since InvalidOperationException might be thrown from other stacks.
Michael Pizzo - MSFT wrote: Have you done performance tests to validate that you are getting a significant advantage in re-using a single ObjectContext over creating each use?
Yes. After instatiating the first ObjectContext, every susequent initialization takes ~40 ms in computer. This measuement includes the context disposal as well. In my usage context, it's way too costly. I'm heavily relying on lazy load, and I don't want to pay this uneccessary overhead.
As a comparison, poor SqlConnection (open + closure) takes ~3ms.
The caching is actually a benefit for me, since I don't mind keep entities around. They tend to be used for the lifetime of my app anyway after their first retrieval.

