2012-06-05 2 views
3

В настоящее время я столкнулся с проблемой, что я пытаюсь создать DAL для моего .NET-приложения, которое позже будет использовать какую-то базу данных NoSQL.
Базы данных NoSQL, которые я оценил к настоящему времени, иногда различаются по типу, который они используют в качестве первичного ключа. Например, MongoDB использует собственный ObjectID, в то время как RavenDB использует общий string. Итак, мой вопрос: как мне создать такой DAL, который может обрабатывать разные типы идентификаторов модели домена.Архитектура DAL, использующая общие модели доменов

Моим первым подходом было создание универсальных моделей доменов. Это выглядело примерно так:

// 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 
    } 
} 

Комментарий в методе DAO-Factory уже описывает эту проблему: я не могу определить T во время выполнения, так как соответствующий код генерируется во время компиляции.

Мой второй и третий подход заключался в определении Id либо object, либо dynamic. RavenDB не мог работать с object, потому что ему нужна строка. Использование dynamic Я не мог передать lambdas в RavenDB API (ошибка компилятора «Дерево выражений не может содержать динамическую операцию»). И создание деревьев выражений вместо использования lambdas - действительно последний выход, потому что это более трудоемкий процесс.

Итак, я полностью застрял и надеюсь, что кто-то может мне помочь. Спасибо заранее.

ОБНОВЛЕНИЕ: Я, наконец, получил RavenDB для работы с object, но это не удовлетворительное решение для использования object.

ответ

2

Вы могли бы решить проблему в статическом классе, если бы знали тип во время компиляции, правильно? Это означает, что, обязательно, вам понадобится одна реализация DaoFactory для каждой базовой базы данных.

Ответ заключается в том, что вы не должны использовать factory pattern - вместо этого вы должны использовать 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>() { /* ... */ } 
} 

Я должен был сделать то же самое и попытался использовать dependency injection pattern для выбора соответствующей реализации для использования во время выполнения, но это на самом деле очень трудно сделать из-за проблемы дженериков. Абстрактная фабрика - лучший способ пойти сюда.

+0

Но теперь я должен прямо сказать компилятору, что я хочу, например, MongoDBFactory, не так ли? Я имею в виду, что если я создаю фабрику, я все равно должен предоставить такой тип: «DaoFactory factory = new MongoDBFactory();' И именно это я и хотел включить в конфигурацию. –

+0

Правда; как я уже сказал, использование DI становится очень сложным с общими интерфейсами. Я знаю, что это может быть сделано (я считаю, что Microsoft Unity, например, делает это); Я просто не уверен, что это то, что вы действительно хотите сделать. В конце концов, вы все равно должны знать тип TId в своем клиентском коде, не так ли? По всей вероятности, если вы перемещаетесь между совершенно разными базами данных, то перекомпиляция кода будет наименьшей из ваших проблем. –

+0

Я думаю, вы правы, что мне придется столкнуться с некоторыми проблемами на более высоких уровнях. И если DI действительно так сложно, я думаю, что это не выбор. Я не хотел мигрировать между совершенно разными базами данных, но только между похожими (например, только хранилищами документов). Я проверю решение с помощью DI, и если это не удовлетворительно, я, вероятно, унифицирую тип id на 'object'. Спасибо за вашу помощь. +1 за предоставленный ответ. –

Смежные вопросы