Johannes Egger
Johannes Egger

Reputation: 4041

DAL architecture using generic domain models

Currently I'm facing the problem, that I try to design a DAL for my .NET application, which will later use some sort of NoSQL database.
The NoSQL databases I evaluated by now sometimes differ in the type they use as primary key. For example, MongoDB uses a proprietary ObjectID while RavenDB uses a common string. So my question is, how do I design such a DAL which can handle different types of domain model id's.

My first approach was to make generic domain models. This looked something like this:

// Domain Model
public class Filter<TId> {
  public TId Id { get; set; }
  // ...
}

// DAO-interface
public interface IFilterDao<TId> {
  bool Persist(Filter<TId>);
  // ...
}

// This is where the problems begin
public static class DAOFactory {
  public static IFilterDAO<T> GetFilterDAO<T>() {
    // Implementation of IFilterDAO<T> can't be instantiated because types must be known at compile time
  }
}

The comment in the DAO-Factory method already describes the problem: I can't define T at runtime, because the corresponding code is generated at compile time.

My second and third approach was to define the Id to be either object or dynamic. RavenDB couldn't work with object, because it needs a string. Using dynamic I couldn't pass lambdas to the RavenDB API (Compiler error "An expression tree may not contain a dynamic operation" occured). And building expression trees instead of using lambdas is really the last way out because it's way more time-consuming.

So I'm totally stuck and I hope someone can help me out. Thanks in advance.

UPDATE: I finally got RavenDB to work with object, but it's not a satisfying solution to use object.

Upvotes: 3

Views: 400

Answers (1)

Lars Kemmann
Lars Kemmann

Reputation: 5674

You could solve the problem in the static class if you knew the type at compile time, correct? That means that, necessarily, you will need one DaoFactory implementation for every underlying database.

The answer is that you shouldn't be using the factory pattern - instead, you should be using the abstract factory pattern.

public class Filter<TId> { 
  public TId Id { get; set; } 
} 

public interface IFilterDao<TId> { 
  bool Persist(Filter<TId>); 
} 

// Note: Can't be static since polymorphism requires an instance!
public abstract class DaoFactory<TId> {
  public abstract IFilterDao<TId> GetFilterDao<TId>();
}

public sealed class MongoDBDaoFactory : DaoFactory<ObjectID> {
  public override IFilterDao<ObjectID> GetFilterDao<ObjectID>() { /* ... */ }
}

public sealed class RavenDBDaoFactory : DaoFactory<String> {
  public override IFilterDao<String> GetFilterDao<String>() { /* ... */ }
}

I've had to do similar things and tried using the dependency injection pattern for selecting the appropriate implementation to use at runtime, but that's actually very hard to do because of the generics issue. Abstract factory is the best way to go here.

Upvotes: 2

Related Questions