Является ли подход Multi-DAL подходом? - PullRequest
0 голосов
/ 16 апреля 2010

Работа над уровнем доступа к данным / модели в этом небольшом проекте MVC2 и попытка придумать вещи для будущих проектов.

У меня есть база данных с некоторыми базовыми таблицами, и у меня есть классы на уровне модели, которые их представляют. Мне явно нужно что-то, чтобы соединить два. Самый простой - предоставить своего рода «провайдера», который может выполнять операции с базой данных и возвращать объекты.

Но это для веб-сайта, который потенциально будет использоваться "много" (я знаю, очень общий), поэтому я хочу кешировать результаты со слоя данных и обновлять кеш по мере генерирования новых данных.

Этот вопрос касается того, как лучше всего подойти к проблеме двойного DALS. Тот, который возвращает кэшированные данные, когда это возможно, и переходит на уровень данных, когда отсутствует кеш Но что более важно, как интегрировать основной провайдер (что входит в базу данных) с уровнем кэширования, чтобы он тоже мог полагаться на кэшированные объекты, а не создавать новые.

Сейчас у меня есть следующие интерфейсы:

IDataProvider используется для доступа к базе данных. Это касается не значения объектов, которые он производит, а просто способа их производства.

interface IDataProvider{
    // Select, Update, Create, et cetera access
    IEnumerable<Entry> GetEntries();

    Entry GetEntryById(int id);
}

IDataManager - это слой, который находится поверх слоя IDataProvider и управляет кешем

interface IDataManager : IDataProvider{
    void ClearCache();
}

Обратите внимание, что на практике реализация IDataManager будет иметь полезные вспомогательные функции для добавления объектов в соответствующие хранилища кэша. (В будущем я могу определить другие функции интерфейса)

Полагаю, то, что я ищу, - лучший способ вернуться к циклу из реализаций IDataProvider, чтобы они могли получить доступ к кешу. Или совсем другой подход может быть в порядке? В данный момент я не очень заинтересован в продуктах сторонних производителей, так как мне интересен дизайн этих вещей гораздо больше, чем эта конкретная реализация.

Редактировать: я понимаю, что название может быть немного вводящим в заблуждение. Я прошу прощения за это ... не уверен, как назвать этот вопрос.

1 Ответ

0 голосов
/ 16 апреля 2010

Лично я в настоящее время использую NHibernate, который обрабатывает кеширование для вас. В прошлом я делал нечто похожее на то, что вы пытаетесь сделать, однако мне никогда не приходилось отделять слой кэширования от слоя дао. Есть ли какая-то причина, по которой вам нужно отделить их? Я полагаю, что это имело бы смысл, если у вас существенно разные потребности в кэшировании в зависимости от типа объекта. Во всяком случае, если предположить, что это необходимо, вот как я буду делать это на основе прошлого опыта. Во-первых, давайте предположим, что у нас есть следующие классы: PersistentObject, который является базовым объектом, у которого есть хотя бы целочисленное свойство с именем "ID"

public class PersistentObject
{
   public int ID { get; set; }
}

Теперь скажите, что у вас есть тип выборки, который вы хотели бы сохранить:

public class SampleObject : PersistentObject 
{ 
    public string SomeValue { get; set; }
}

Вместо «DataProvider» у меня есть простой интерфейс хранилища:

public interface IRepository<T> where T : PersistentObject
{
    T Get(int id);        
    void Save(T e);
    void Delete(T e);
}

Как насчет того, чтобы вместо вашего интерфейса IDataManager у вас был абстрактный класс, который вы можете реализовать, который является хранилищем, которое обрабатывает кэширование (у меня есть свой собственный класс "CacheManager", который я здесь использую, он может быть реализован любым числом путей):

public abstract class CacheRepository<T> : IRepository<T> where T : PersistentObject
{
    private const string CacheKeyPrefix = "RepoCache-";
    private string GetCacheKey(int id)
    {
        return CacheKeyPrefix + typeof(T).FullName + "-" + id.ToString();
    }

    public T Get(int id)
    {
        string cacheKey = GetCacheKey(id);
        T obj = CacheManager.GetItemFromCache<T>(cacheKey);
        if (obj == null)
        {
            obj = this.GetData(id);
            if (obj != null)
                CacheManager.AddItemToCache(obj, cacheKey);
        }
        return obj;
    }

    public void Save(T obj)
    {
        string cacheKey = GetCacheKey(obj.ID);
        this.SaveData(obj);
        CacheManager.AddItemToCache(obj, cacheKey);
    }

    public void Delete(T obj)
    {
        string cacheKey = GetCacheKey(obj.ID);
        this.DeleteData(obj);
        CacheManager.RemoveItemFromCache(cacheKey);
    }

    protected abstract T GetData(int id);
    protected abstract void SaveData(T obj);
    protected abstract void DeleteData(T obj);
}

Вы заметите, что единственные открытые члены - это методы, реализующие IRepository. Существует 3 абстрактных метода, которые должны быть реализованы для доступа к данным отдельным репозиторием. Таким образом, мы можем сделать это здесь для нашего SampleObject:

public class SampleObjectRepository : CacheRepository<SampleObject>
{
    protected override SampleObject  GetData(int id)
    {
        //do some loading
        return new SampleObject();
    }

    protected override void  SaveData(SampleObject obj)
    {
        //do some saving
    }

    protected override void  DeleteData(SampleObject obj)
    {
        //do some deleting
    }
}

Наконец, вот как вы будете использовать этот код:

public class UsageSample
{
    public UsageSample()
    {
        //save a new object
        SampleObjectRepository repo = new SampleObjectRepository();
        SampleObject sampleObj = new SampleObject();
        repo.Save(sampleObj);

        //load an object by ID
        int id = sampleObj.ID;
        sampleObj = repo.Get(id);

        //delete an object
        repo.Delete(sampleObj);
    }
}

Это становится значительно сложнее, когда вы начинаете говорить о возврате коллекций и запросах, но это, по крайней мере, упрощенное начало. Вы уверены , что вас не интересуют сторонние решения? :-) NHibernate отлично справляется со всем этим.

...