DATS2/BATSLite DAO/ORM Library

If you are from the world of Java the term ‘Data Access Object’ is probably more familiar to you.  In J2EE they are considered best practice as the advantage of using DAOs is that any business/domain objects that contains operation specific logic do not need to be aware of the actual physical data implementation of the system.  Thus, if any changes are made to the data sources layers they shouldn’t affect the (usually) more complicated business/domain logic.  They are also exceptionally useful for enforcing rules on the data and how it is to be used in general. 

Some developers consider DAOs and ORMs a different paradigm, however I have yet to see a convincing argument to say that they are substantially different fundamentally and the differences seem to stem from marketing convenience and personal choice than any real semantic difference. 

In this area .NET has a little catching up to do, although there are plenty of implementations available on the web (including a .NET port of the Java Hibernate tool).  However despite this many firms prefer to either create their own or bodge something together that invariably ties the project to a specific data source. 

History

Recognising this rather early in 2002 I decided to step back and write an implementation to fit the requirements of a personal project, but that I would be able to evolve over time.  I developed the original with the help of a friend of mine (Andy “Smellyhippy” Jump) in my personal time and he and I went on to successfully implement it into an EPOS system and then a later into a CMS before Andy moved on and I continued with various other systems for clients as my contracts came and went.  A cut down version of the largest and most complicated revision known as BATS (used in a CMS system) is currently in use by a UK utilities firm.  A version of “BATSLite” (butchered to avoid copyright issues) will be available soon for completeness on this page; I am currently trying to ensure that the code fully works despite several items specific to the client being removed. 

A New Breed

Dats Core Diagram. Click for larger image. When the new year came around a few individuals came to me asking if a newer less ‘hacked’ version would be made available.  After some conversation I decided that it was about time that a re-write was due and set about re-creating the core.  The result of which is ‘DATS2’.

DATS2 *is* another BATS implementation; however I felt that the rename was essential for various reasons (including legal ones).  It represents a complete re-write, restructure and departure from the quirks that have over time made their way into the BATS code set.  The implementation as it currently stands is also somewhat specific to the requirements of the individuals who came to me requesting the change; as such this version more or less represents the first ‘revision’ so to speak.  (More accurately I made it work to a basic level and handed it over). 

So I am releasing the current version to the public domain.  I may create a sourceforge place for it in the coming months as revisions from the few individuals already in possession of the code add and revise it.  Please feel free to do the same!  This version represents the cleanest and rawest condition I have ever released DATS and it’s predecessors in and I hope this benefits the project.  There is currently no documentation, for which I can only apologise, yet I hope that over time this situation will be rectified. 

Oh... one more small thing, due to the requirements of those who essentially commissioned this work, the supplied (incomplete) DAL generates the SQL queries in a JIT fashion.  This was due to limitations on their behalf and nothing to do with my own choice.  I am planning a CLR stored procedure implementation of the DAL for use with SQL2005 and a WebService DAL in the future - depends on what comes up though...

DATS2.zip

Future Implementation Thoughts

  1. Add associated objects functionality.
    This would allow you to associate other DATS based objects to a DATS object.  This is something I have been thinking about for a while as part of BATS and there have been instances where this would have been an exceptionally useful feature.
     
  2. Create a Facade system to allow for smoother Object Oriented implementations.
    The 'object-relational impedance mismatch' problem is a nasty issue that everyone seems to dislike and a solution is certainly required.  An easy way out includes some thoughts bouncing around in my head to help this somewhat.  
     
    Other proposed solutions include the Nordic O/R dbms model (see the article in Architecture Journal 8), which while seems like a good solution, involves a lot of work for the everyday programmer whenever a new object needs to be created... the lack of Multiple Inheritance in .NET also makes this issue sizeable.  DATS has always aimed to reduce the the amount of code needed to be written by the developer so the Nordic model is out for DATS.  Another issue is that the Nordic model requires an underlying RDBS - which also flies in the face of the DATS philosophy of detachment from underlying data implementations.
     
    Suggestions on this are most welcome...

BATSLite

Until I can make BATSLite available, here is the class diagram.  Notice the complexity difference.

BATSLite diagram.  Click for larger image.



[10/5/2007] Anon: Ref: dats2batslite
Hey!

What's your views on using a DataMapper style approach rather than the Active Record style approach used by DATS?

What I personally like about the DataMapper approach is that the Domain objects aren't tied 1:1 to a persistence engine.  I've put together a prototype of this concept and though as not fully featured as your DATS engine, seems to work very well.

It also maps directly to objects using a DataReader rather than via a DataSet, using DynamicMethods to get/set properties (much faster than reflection).  From experience, can you see any issues of using this style of approach rather than a DataSet?  One of the things I can think of would be you'd have to encapsulate your own Unit of Work engine rather than using the built in one you'd get with a DataSet.
[12/13/2007] Matt "Moridin8" Warren: Ref: Ref: dats2batslite

The active record model used by DATS is a prefered one by many of the organisations I have worked at and is also how Linq to SQL works.  I must admit I am not familiar with the DataMapper style approach used by Ruby, so I can not really comment on this.  The 1:1 mapping is intentional.

The reason for using DataSets in DATS is purely for familiarity in concern to other users and systems that require DataSets to be used.  99.99% of all .NET applications use DataSet's so moving outside of this didn't seem a logical choice at the time of creating DATS.  Yes, DataReaders are more efficient, as are dynamic methods, however another point to DATS is that it's meant to be a reflection engine so as to reduce productivity time and hand-coding... dynamic methods (if by this term you mean code Emiting IL statements on the fly) would add a complexity level to DATS that would have been unwelcome.  
   You could if you wish use a DataReader to populate DATS objects, but I don't really see much advantage to it in a RAD environment - especially as a DataSet uses a DataReader itself.  So yes, DataSets are already there and are well tested and well used and everyone knows how to use them.  So I stuck with that.

It's all very nice to create everything from scratch - but sometimes you have to ensure that everyone and his dog can grasp the code set you create.  Departure from this can cause issues down the line with maintainability and reliability.

You have however given me something to look into... thanks.  ;)

[12/24/2007] Anon: Ref: dats2batslite

Hi,

I'd also suggest looking into the LINQ to entities framework.  LINQ to SQL only maps to SQL Server - obviously if you are using only MS products then LINQ to SQL is fine.

Other things you need to be wary about is the Attach API in LINQ to SQL for distributed systems.  LINQ to SQL will not allow an entity to be shared across DataContext objects, this makes sense due to the concurrency checks being dealt with by the DataContext.

Objects can be detached by serializing them, but the default ORM designer model will create circular references.  You could either alter the model to not provide circular references, or you could use a DTO pattern and copy the values into the DTO and have them as specific objects in your WCF/Web Service API.

[12/24/2007] Anon: Ref: dats2batslite

I can provide a very simple API that wraps and creates dynamic methods for property getters and setters.  I used this in my prototype ORM (used to further my knowledge of such products and what's involved).

It's significantly faster than reflection too.

[12/24/2007] Anon: Ref: dats2batslite

I can provide a very simple API that wraps and creates dynamic methods for property getters and setters.  I used this in my prototype ORM (used to further my knowledge of such products and what's involved).

It's significantly faster than reflection too.