Click here to Skip to main content
Click here to Skip to main content

db4objects Domain and DAL

, 16 Aug 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
How to make the domain independent from db4objects.

Introduction

For quite some time I've been reading articles about NoSQL databases and finally got a project which was planned to be using db4objects. This OODBMS has a very useful feature called transparent activation which is lazy loading. It requires certain functionality from the stored objects, but this contradicts a well known idea that the domain should not depend on how its objects are persisted.

Using the code

The code is very simple and the main idea is not about the coding, but about the design.

The first solution I came up with was based on my experience with NHibernate where each domain class looks like this:

public class Book  
{
    public virtual string Name { get; set; }
}

NHibernate will take care of creating the Book class descendant with all the required modifications. db4o doesn't do this for us so we need to implement the IActivatable interface ourselves, and there are options:

  1. Write a code generator
  2. Create a descendant for each class in DAL adding the required changes
  3. Create a common base class in the domain and implement the required changes there

Option 1 is very complex and in general can be considered as an overhead unless we are db4o developers Smile | :)

Option 2 seems reasonable, but we will have to copy-paste a lot of stuff over and over again as there is no multiple inheritance in C#.

Here is how a descendant will look like:

public class DALBook : Domain.Book, IActivatable
{
    public virtual string Name
    {
       get
       {
           Activate(ActivationPurpose.Read);
           return base.Name;
       }
       set
       {
           Activate(ActivationPurpose.Write);
           base.Name = value;
       }
    }

/*
    Here is the part that is required for the transparent activation
    which is identical for each DAL class.
*/
    [Transient]
    private IActivator _activator;

    public void Activate(ActivationPurpose purpose) 
    {
        if(_activator != null) 
        {
            _activator.Activate(purpose);
        }
    }
    public void Bind(IActivator activator) 
    {
        if (_activator == activator)
        {
            return;
        }
        if (activator != null && null != _activator)
        {
            throw new System.InvalidOperationException();
        }
        _activator = activator;
    }
}

It seems desirable to make a common superclass which will implement the Activate and Bind methods.

Option 3 means we bind the domain and the DAL - a very inflexible solution and simply a bad idea:

  1. Domain will "know" about its persistence
  2. Unrelated classes will get a common superclass
  3. etc.

Let's change the class to an interface:

public interface Book  
{
    string Name { get; set; }
}

Now in DAL, we can make a proper hierarchy with a base class implementing the logic really common for every persistable object.

internal abstract class Db4oBase: IActivatable
{
    [Transient]
    private IActivator _activator;

    public void Activate(ActivationPurpose purpose) 
    {
        if(_activator != null) 
        {
            _activator.Activate(purpose);
        }
    }
    public void Bind(IActivator activator) 
    {
        if (_activator == activator)
        {
            return;
        }
        if (activator != null && null != _activator)
        {
            throw new System.InvalidOperationException();
        }
        _activator = activator;
    }
}

internal class DALBook : Db4oBase, Domain.IBook
{
    private string name_;
    public virtual string Name
    {
       get
       {
           Activate(ActivationPurpose.Read);
           return name_;
       }
       set
       {
           Activate(ActivationPurpose.Write);
           name_ = value;
       }
    }
}

All DAL classes are marked as internal as DAL clients should know only about the domain interfaces thus a solution to instantiate concrete classes based on the desired interfaces should be implemented. For instance:

public static class DAOFactory 
{
    public static T CreateDomainObject<T>()
    {
        string dalClass = string.Format("DAL.{0}", typeof(T).Name.Substring(1));
        return (T)Type.GetType(dalClass).GetConstructor(Type.EmptyTypes).Invoke(null);
    }
}

Using DAOFactory, we can create objects and treat them based on their interfaces like:

Domain.IBook book = DAL.DAOFactory.CreateDomainObject<Domain.IBook>();

Points of interest

The domain can be a set of interfaces with the DAL being a set of concrete classes with completely encapsulated implementation which, itself, can have whatever class hierarchy required to eliminate copy-paste and avoid unnecessary cohesion.

History

  • 14 AUG 2011 - Initial version.
  • 16 AUG 2011 - Fixed left angle bracket.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Raspberry Man
Software Developer Microsoft
United States United States
LNG: Turbo Pascal → Delphi → C/C++ → C# & ASP.NET
 
DBE: MS Access → MS SQL Server 2000 → Linter → MySQL → MS SQL Server 2005 → MS SQL Server 2008 & Db4o & Oracle & Teradata
 
ENV: Turbo Pascal → Delphi → C++Builder 5/6 → VS2005 → VS2008 → VS2010

Comments and Discussions

 
QuestionWhere do you write business logic? Pinmemberasthalas15-Aug-11 22:11 
AnswerRe: Where do you write business logic? PinmemberRaspberry Man15-Aug-11 22:36 
QuestionGNU PinmemberDewey15-Aug-11 21:30 
Ugghhh...

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 16 Aug 2011
Article Copyright 2011 by Raspberry Man
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid