tags:

views:

105

answers:

2

Question - What is a good best practice approach for how can I save/keep-in-sync an jn-memory graph of objects with the database?

Background:

That is say I have the classes Node and Relationship, and the application is building up a graph of related objects using these classes. There might be 1000 nodes with various relationships between them. The application needs to query the structure hence an in-memory approach is good for performance no doubt (e.g. traverse the graph from Node X to find the root parents)

The graph does need to be persisted however into a database with tables NODES and RELATIONSHIPS.

Therefore what is a good best practice approach for how can I save/keep-in-sync an jn-memory graph of objects with the database?

Ideal requirements would include:

  • build up changes in-memory and then 'save' afterwards (mandatory)
  • when saving, apply updates to database in correct order to avoid hitting any database constraints (mandatory)
  • keep persistence mechanism separate from model, for ease in changing persistence layer if needed, e.g. don't just wrap an ADO.net DataRow in the Node and Relationship classes (desirable)
  • mechanism for doing optimistic locking (desirable)

Or is the overhead of all this for a smallish application just not worth it and I should just hit the database each time for everything? (assuming the response times were acceptable) [would still like to avoid if not too much extra overhead to remain somewhat scalable re performance]

A: 

Short answer is that you can still keep a graph (collection of linked objects) of the objects in memory and write the changes to the database as they occur. If this is taking too long, you could put the changes onto a message queue (but that is probably overkill) or execute the updates and inserts on a separate thread.

James Westgate
there's no obvious out-of-the-box approach then James with .net? For example ado.net, or linq-to-sql, or enterprise framework doesn't provide an easy way to solve, or a pattern to follow to solve?
Greg
+1  A: 

I'm using the self tracking entities in Entity Framework 4. After the entities are loaded into memory the StartTracking() MUST be called on every entity. Then you can modify your entity graph in memory without any DB-Operations. When you're done with the modifications, you call the context extension method "ApplyChanges(rootOfEntityGraph)" and SaveChanges(). So your modifications are persisted. Now you have to start the tracking again on every entity in the graph. Two hints/ideas I'm using at the moment:

1.) call StartTracking() at the beginning on every entity

I'm using an Interface IWorkspace to abstract the ObjectContext (simplifies testing -> see the OpenSource implementation bbv.DomainDrivenDesign at sourceforge). They also use a QueryableContext. So I created a further concrete Workspace and QueryableContext implementation and intercept the loading process with an own IEnumerable implementation. When the workspace's consumer executes the query which he get with CreateQuery(), my intercepting IEnumerable object registers an eventhandler on the context's ChangeTracker. In this event handler I call StartTracking() for every entity loaded and added into the context (doesn't work if you load the objects with NoTrakcing, because in that case the objects aren't added to the context and the event handler will not be fired). After the enumeration in the self made Iterator, the event handler on the ObjectStateManager is deregistered.

2.) call StartTracking() after ApplyChanges()/SaveChanges()

In the workspace implementation, I ask the context's ObjectStateManager for the modified entities, i.e:

var addedEntities = this.context.ObjectStateManager.GetObjectStateEntries(EntityState.Added); --> analogous for modified entities

cast them to IObjectWithChangeTracker and call the AcceptChanges() method on the entity itself. This starts the object's changetracker again.

For my project I have the same mandatory points as you. I played around with EF 3.5 and didn't find a satisfactory solution. But the new ability of self tracking entities in EF 4 seems to fit my requirements (as far as I explored the funcionality).

If you're interested, I'll send you my "spike"-project.

Have anyone an alternative solution? My project is a server application which holds objects in memory for fast operations, while modifications should also be persisted (no round trip to DB). At some points in code the object graphs are marked as deleted/terminated and are removed from the in-memory container. With the explained solution above I can reuse the generated model from EF and have not to code and wrapp all objects myself again. The generated code for the self tracking entities arises from T4 templates which can be adapted very easily.

Thanks a lot for other ideas/critism

andi
that sounds very interesting andi - is this a popular/well used part of EF? Is the implemention of this EF feature solid? (like is it just a recent feature that has been released, or has this been in EF since the begining)
Greg