Over the course of quite a few posts during the last several weeks I’ve shared source code that adds up to an implementation for EntityBag<T>. Piecing together a project from all those snippets, though, would be a pretty painful task, so I put the whole thing together in a zip file and posted it up at the new MSDN Code Gallery site: http://code.msdn.microsoft.com/entitybag/
Since I finished the series, though, I’ve done a bit more testing on the project and ran into a small bug. ContextSnapshot includes a copy of the connection string from the context which is the initial source of the EntityBag, and it uses that connection string to create its own internal context for tracking changes to the graph. In my initial testing, I always constructed the context by passing a connection string to the constructor, and everything worked fine, but an even more common pattern is to use the parameterless constructor which causes the context to have a connection string of the form: name=”containerName” and the full connection string is actually in the application’s config file. The problem with this is that on the client the config file would not be present. So, we add the following code to the ContextSnapshot.ConnectionString setter after the line which constructs the connection string builder:
if ((csBuilder.Name != null) && (csBuilder.Name != ""))
// lookup the actual connection string from the config file
string connectionString = ConfigurationManager.ConnectionStrings[csBuilder.Name].ConnectionString;
csBuilder = new EntityConnectionStringBuilder(connectionString);
The project file on code gallery includes this fix. I’ve also had some questions from folks who were having trouble getting a WCF service working using EntityBag, so I included a sample service as well.
Creating an EntityBag-based Service
I’m no WCF expert, but I’ve been able to muddle my way through. It seems like it might be useful to point out some of the trickier steps involved in putting together the sample:
- Known types for the service methods are an issue—especially since EntityBag is generic and can contain a graph of many entity types. This is something which will be addressed automatically in the next release, but for now this is worked around with a static method (GetKnownEntityTypes) and an operation contract attribute which points to it as described in this previous post.
- If you create your entities in a separate DLL like I’ve done in the sample, then you need to copy the connection string from the model.dll’s app.config file to the web.config for the service.
- If you are going to use regular metadata files, you need to make sure they are in the right directory--otherwise, you can embed them as resources, but then you need to deal with a beta 3 bug by building with the metadata not embedded first and then rebuilding set to embed.
- One common and frustrating problem is that it’s easy for the size of the message to grow beyond the default maximum message size. This can be addressed by changing the maxReceivedMessageSize in the app.config for the client and in the web.config for the service.
- Finally, it’s important to make sure the service is set to re-use referenced types. This is turned on by default with VS 2008, but it’s worthwhile to make sure that it is on, and of course you need to reference system.data.entity.dll, perseus and your model on the client before adding the service reference.
With all of this we have a decent proof of concept, but clearly there’s a lot of room for additional improvements. Here are a few ideas both to give you an idea of current limitations and future possibilities:
· It needs to be tested against a wider array of models.
o Entities with complex types will likely present problems because there are currently limitations in the CurrentValues and OriginalValues records on ObjectStateEntry when dealing with properties that are complex types.
o Associations with referential integrity constraints likely need careful ordering which the system doesn’t yet impose.
· There are various limitations due to bugs or not yet implemented features in the Entity Framework.
o Entities used with EntityBag must implement IEntityWithKey. Classes generated by the system implement this interface, but IPOCO classes are not required to implement it. Unfortunately, an API change in beta 3 makes it impossible to do certain operations in a general-purpose component unless the entities in question implement the interface. A future release will remedy the problem, and it will be possible to remove the requirement.
o Currently the system uses reflection to set the EntityKey property on IRelatedEnd when the end in question is an EntityReference. Future releases will remove that requirement. For the most part this isn’t an issue, but it could create partial trust issues—I haven’t yet had a chance to investigate fully.
· The message size could be further optimized.
o Right now the system can’t distinguish between the serialization used when transmitting from the service to the client and that used when transmitting from the client back to the service. This causes unnecessarily large messages because when transmitting to the client you clearly want to include everything, but when transmitting back to the service in most cases you could skip all unchanged entities.
o The component could also take advantage of work underway for the Entity Data Source Control to store and transmit only the minimum set of original values which the system needs rather than a whole copy of the original entity. Of course in some cases you will need the whole entity anyway because business logic may prevent constructing an entity with only this minimum set of properties, but in many cases this would be a useful optimization.
· Additional steps could be taken to strengthen a web service’s contract.
o Events or some other mechanism could be added to allow validation when an EntityBag is passed from the client back to the service for updates.
o Even better, code could be generated to create a stronger contract and just use EntityBag as an internal storage/serialization mechanism.
I’m sure there are other things we could do as well, but that’s probably enough to set you thinking. As always, if you have questions or ideas, please don’t hesitate to share them.