How do I design a Data Access Layer appropriately?

Munish Goyal picture Munish Goyal · Jan 6, 2011 · Viewed 20.2k times · Source

I have the following Data Access Layer (DAL). I was wondering if it's set up correctly, or if I need to improve it?

public class User 
{

}

//Persistence methods
static class UserDataAccess
{
   UsersDAL udal = // Choose SQL or FileSystem DAL impl.


   InsertUser(User u)
   {
      // Custom logic , is 'u' valid etc. 

      udal.Insert(u);
   }
}

abstract class UsersDAL
{    
   GetUserByID();
   InsertUser(u);
   ...
}

// implementaitons of DAL

static class UsersSQLStore : UsersDAL
{

}

static class UsersFileSystemStore : UsersDAL
{

}

I separated the storage layer from the User class to access methods collection which further call any custom DAL.

Is use of static in DAL implementation correct?

Please suggest corrections or ways I can make this better. I don't have a lot of experience with writing code in layers.

Answer

Klaus Byskov Pedersen picture Klaus Byskov Pedersen · Jan 6, 2011

None of those classes should be static. I don't think you should name your classes DAL either, because its short for Data Access Layer, and a class in itself is not a layer (in my mind at least). You can use the widely adopted term repository instead. I suggest you do something like the following:

public class User{

}

public abstract class UserRepository{
    public abstract void InsertUser(User user);
}

public class SqlUserRepository : UserRepository{
    public override void InsertUser(User user)
    {
      //Do it
    }
}

public class FileSystemUserRepository : UserRepository{
    public override void InsertUser(User user)
    {
      //Do it
    }
}

public class UserService{
    private readonly UserRepository userRepository;

    public UserService(UserRepository userRepository){
        this.userRepository = userRepository;
    }

    public void InsertUser(User user){
        if(user == null) throw new ArgumentNullException("user");
        //other checks
        this.userRepository.InsertUser(user);
    }
}

Note that the UserService is injected with an instance of the abstract class UserRepository in its constructor. You can use a Dependency Injection (DI) framework to do this for you automatically, such as Windsor Castle from Castle Project. It will allow you to specify a mapping from abstraction (UserRepository) to concrete implementation (eg. SqlUserRepository) in a configuration file, or in code.

Hope this points you in the right direction, and please ask if you need more information.