For the past year or two I've been crystallizing some thoughts about frameworks based on my experiences developing and using ASInet 2, Philidor and Morphy (applications and frameworks I developed for my company). Although these frameworks are useful, they rely too heavily on ADO.NET DataSets and DataTables, expose too many low-level tasks to the developer, have a steep learning curve, and generate a lot of code which leads to long startup times and low productivity.
With these thoughts in mind, in my spare time (!) in the last year I've been working on a new framework, tentatively called "Slipjig", that attempts to address these concerns. Slipjig is based on .NET 2.0 and is much more dynamic than my previous efforts. Here are the major design ideas:
-
The entities contain their own data, rather than binding to DataRows. LINQ will enable us to query an entity tree as if it were a database.
-
Entities have direct references to other entities, providing for parent, child, peer, and many-to-many relationships. The framework can load and save an entire entity tree automatically.
-
The entities use attributes to specify object-relational mapping information, rather than code in the entity or in separate but related data access classes. This reduces the project footprint considerably and yields faster startup times.
-
A property on the entity controls how the entity will get persisted. Though normally this property is set automatically based on how the entity is used, the developer has complete control over how each entity is persisted.
-
The data access layer eschews DataSets completely. Instead, it uses dynamically-generated mapping classes to move data between entities and ADO.NET DataCommands/DataReaders. The mapping classes are generated only on first data access for each entity, yielding even faster startup times. So if you are unit testing a code change in only one module out of 100, the framework only generates and loads the necessary code.
-
The data access layer uses the concept of a "loader" - a class that pulls data from a data source and populates a number of entities from it. There are different loaders for different scenarios, and developers can write their own loaders. The data access layer provides implicit transaction support with no need for the developer to do anything.
-
The data access layer automatically batches commands for better performance. It also observes a consistent save order for the tables, to prevent deadlocks in the database. The framework uses a table and stored procedure to assign its own keys, rather than use identity columns. This provides a number of advantages, chief among them the ability to assign keys in advance of hitting the database. The framework grabs a batch of keys from the database when it needs to, and doles them out to entities as needed, rather than hit the database for each key. This avoids contention on the key table. Keys are assigned to the entities automatically - the developer does not need to worry about this.
The current status is that I'm working on the loaders, to get them loading the entire entity tree. I'm making changes as necessary to support that. The "save" side of things is working, though I have a few to-dos there too: getting the table save order and command batching fully implemented, and providing more hooks for the developer to control exactly which parts of an entity tree get persisted.
If you're a developer and want to take a look at the framework, give me a shout and I'll get you SVN access :-)