Using DB4Objects as a prototyping tool. Part I

I have been looking at DB4Objects http://db4objects.com as a persistence layer that could help with prototyping work. If you are not familiar with db4objects ( DB4O ), it is an object oriented database.  What does that mean?  If I boil it down in laymen’s terms : it is a database without tables or columns.


 Sample of DB4Objects


Here is a sample of storing a simple domain object:





   1: User  user = new User {Username = “testuser”, Password = “password”};
   2: user.Roles = new List<Role> {new Role {RoleType = UserRepositoryTester.RoleType.User}};
   3: using( IObjectContainer objectContainer = PersistanceContainerFactory.Create())
   4: {
   5:     objectContainer.Store(user);
   6: }

The magic sauce is in line 5. I did not have to do anything to setup how to save a User object in the database.  It just serializes the object to the database. No need to worry about table names, column names or data types. This all comes for free with this engine, allowing a developer to focus on the domain model and the value-add code, rather than data persistence.


Why use it for prototypes?


My thought here is this.  The sooner that I can deliver software, the sooner I can start getting to the actual requirements of what it needs to do. My experience is that once the designers and/or product owners see software in working form, they get inspired to really work on making the most of the application. This could be from a User eXperience perspective or sometimes it is just a realization that they did not know what they needed until they saw it in executable form. It really does not matter why they want to make a change. If the end product of a change is better software, than that is a good thing.  To help facilitate getting to software that can be demonstrated, I think that using a persistence engine like DB4O could really help with the time to delivery.  Once the changes/churn has slowed down, than you can take the time to implement the persistence layer. I think writing business logic rather than persistence code that will be changed later, is the best use of developers time.


There are some Caveats




  • First and foremost using infrastructure technology like DB4O has to be used in a manor that promotes Separation Of Concerns from a dependency and design point of view.
  • You need to use the least common denominators as far as functionality, between the prototyping framework and the production persistence framework.
     

A working sample

The following sample code is available at http://erichexter.googlecode.com/svn/trunk/DB4O-sample/
 
So to keep with test first development, lets look at the tests:


   1: [TestFixture]
   2: public class Given_that_a_user_exist_in_repository:Db4oBaseTester
   3: {
   4:     private IUserRepository repository;
   5:     private User user;
   6:  
   7:     protected override void  OnStartup()
   8:     {
   9:         repository = new UserRepository(objectContainer);
  10:         user = new User {Username = “testuser”, Password = “password”};
  11:         user.Roles = new List<Role> {new Role {RoleType = UserRepositoryTester.RoleType.User}};
  12:         objectContainer.Store(user);
  13:     }
  14:     [Test]
  15:     public void When_a_linq_query_is_executed_the_user_should_be_returned()
  16:     {
  17:         IEnumerable<User> users = from User u in repository.Query()
  18:                                   where u.Username.Equals(“testuser”) && u.Roles.Count == 1
  19:                                   select u;
  20:         IList<User> userList = new List<User>(users);
  21:  
  22:         Assert.That(userList.Count, Is.EqualTo(1));
  23:     }
  24:     [Test]
  25:     public void When_a_user_is_deleted_the_user_should_be_removed_from_the_repository()
  26:     {
  27:         repository.Delete(user);
  28:         
  29:         IObjectSet retrievedUser = objectContainer.QueryByExample(user);
  30:         Assert.That(retrievedUser.Count, Is.EqualTo(0));
  31:     }
  32:     [Test]
  33:     public void When_a_username_is_supplied_the_repository_should_return_the_user()
  34:     {
  35:         User retrivedUser = repository.Get(user.Username);
  36:  
  37:         Assert.That(user,Is.EqualTo(retrivedUser));
  38:     }
  39:     [Test]
  40:     public void When_the_user_object_is_changed_the_repository_should_save_the_changes()
  41:     {
  42:         user.Username += “1″;
  43:         repository.Save(user);
  44:  
  45:         User retrievedUser = (User) objectContainer.QueryByExample(new User() {Username = user.Username})[0];
  46:  
  47:         Assert.That(user, Is.EqualTo(retrievedUser));
  48:     }
  49:     protected override void OnTearDown()
  50:     {
  51:         objectContainer.Delete(user);
  52:     }
  53: }
Here I have implemented some basic functionality of a persistence engine.  My goal was to provide an interface which 
could be used to deliver the bare minimum persistence layer so that I can concentrate on user defined features.  
Here is the implementation using DB4Objects.  The IObjectContainer is a DB4o interface which is returned when you open up a new db4o database.
 


   1: public class UserRepository : IUserRepository, IDisposable
   2: {
   3:     private readonly IObjectContainer objectContainer;
   4:  
   5:     public UserRepository(IObjectContainer ObjectContainer)
   6:     {
   7:         objectContainer = ObjectContainer;
   8:     }
   9:  
  10:     public void Dispose()
  11:     {
  12:         objectContainer.Close();
  13:         objectContainer.Dispose();
  14:     }
  15:  
  16:     public void Save(User user)
  17:     {       
  18:         objectContainer.Store(user);        
  19:     }
  20:  
  21:     public User Get(string ID)
  22:     {
  23:         return GetByUsername(ID);
  24:     }
  25:  
  26:     public IEnumerable<User> Query()
  27:     {
  28:         return objectContainer.Cast<User>();
  29:     }
  30:  
  31:     public void Delete(User user)
  32:     {
  33:         objectContainer.Delete(user);
  34:     }
  35:  
  36:     public User GetByUsername(string username)
  37:     {
  38:         IObjectSet set = objectContainer.QueryByExample(new User() {Username = username});
  39:         if (set.Count >= 1)
  40:             return set[0] as User;
  41:         else
  42:             return null;
  43:     }
  44: }

 


Its all in the LINQ


The biggest challenge to using one persistence framework for prototyping and another for production code boils down to the ability to query the objects being persisted.  That makes me think that without .Net 3.5 and the LINQ features of the languages than too much time would be spent developing a persistence independent querying /criteria domain model to get any real advantages as far as developer productivity.  I believe that the real power comes in by using LINQ to query your objects in your service layer when it uses the repositories. This separation really forces the persistence layer to deal specifically with persistence  work and infrastructure optimizations.  The bigger benefit (than separation of infrastructure concerns)  is that the querying criteria can be moved into a service layer that deals specifically with logic around selecting the appropriate objects or projections. I think LINQ addresses the caveat of the Least Common Denominator for querying syntax. This is a huge win in developer productivity (once you get your head around linq)


Where do we go next?


The next step is to implement a UserRepository which would be acceptable for production. I am not suggesting that DB4O cannot be used in production, but in my world of ecommerce, our operations team is willing to support SQL Server, end of conversation. So I need to focus on that requirement for production ready code. We will look at developing a persistence layer for production in Part II of this series.

Related Articles:

    Post Footer automatically generated by Add Post Footer Plugin for wordpress.

    About Eric Hexter

    I am the CTO for QuarterSpot. I (co)Founded MvcContrib, Should, Solution Factory, and Pstrami open source projects. I have co-authored MVC 2 in Action, MVC3 in Action, and MVC 4 in Action. I co-founded online events like mvcConf, aspConf, and Community for MVC. I am also a Microsoft MVP in ASP.Net.
    This entry was posted in c#, DB4O. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
    • http://schambers.lostechies.com Sean Chambers

      Interesting approach.

      Although, This seems like a lot of extra work for prototyping.

      I personally just use a generic repository with nhibernate, supplying an alternate config for a sqlce database on test runs. A throw away database if you will. This way all I have to do is create the repository implementation to go to production.

      Do you use this a lot or are you testing it out? I would like to know how it works in a real world situation. If it’s not too difficult I would consider giving it a shot myself.

    • erichexter

      @Sean – I am testing this out now and this is the first time I have used it. So far it has less friction than nhibernate, but I have not gotten to the Unit of Work abstraction. I imagine that is where I will have some debt to pay.

      As far as more work, I am not sure I agree with that. I think this is less work than even say nhibernate. There are no mappings to create. There is not database schema to create or push to the different environments. Those things are getting easier to manage, but they take time to get in place and I would personally like to delay that work until after I am demonstrating value in the project. Either way I should be working through these issues in the next few posts and we will see what comes of this crazy idea.