Как я могу контролировать глубину выборки загружаемой datamapper? - PullRequest
2 голосов
/ 29 июля 2009

У меня есть класс datamapper, который будет стремиться загрузить любое свойство, к которому не присоединен атрибут Lazy. У меня есть две сущности, Штат и Страна, Страна имеет обратную зависимость к состоянию в том, что она содержит список всех штатов этой страны, а Штат имеет прямое отношение к Стране в том смысле, что у нее есть свойство Страна, которая активно загружает страну, которая это назначено. Однако, если я попытаюсь получить один из этих объектов, скажем, что State это то, что происходит:

  1. Состояние загружается картографом
  2. Mapper достигает страстного желания Страна
  3. Mapper извлекает страну для этого штата
  4. Mapper загружает страну
  5. Mapper достигает объекта коллекционирования состояний
  6. Mapper загружает список состояний и начинает отображать каждый отдельный, используя кеш, где это возможно.
  7. GOTO 1 для каждого штата, загруженного в страну

Я не знаю, как мне избежать этого цикла. Так что в основном я ищу идеи. Я опубликую любой код, который кто-нибудь спросит, но этот процесс включает в себя ОЧЕНЬ много строк кода, поэтому я не хотел наводнить вопрос кодом.

Заранее спасибо!

Edit:

Хорошо, после следования совету Мэтта Хауэллса и более глубокого изучения паттерна картографа данных Мартин Фаулер действительно говорит о циклической ссылке на стр. 169 и 170. Он предлагает использовать пустой объект, загрузить его в карту идентификации и вернуть его таким образом остановка рекурсивной загрузки. Я прочитал этот абзац около 1000 раз и до сих пор не понимаю, как это останавливает загрузку, и, кроме того, я теряюсь в отношении того, когда и как я узнаю, когда загрузить этот пустой объект в мою карту идентификации. Я прошу прощения за то, что был здесь плотным, но кажется, что он летит прямо над моей головой.

Еще раз спасибо.

Ответы [ 3 ]

2 голосов
/ 29 июля 2009

Рассмотрите возможность загрузки объектов через репозиторий, который отслеживает, какие объекты были загружены.

Редактировать: Если вы делаете свой собственный ORM (и даже если нет), я настоятельно рекомендую книгу Мартина Фаулера «Шаблоны архитектуры корпоративных приложений». Я смутно припоминаю, как он говорил об этой петлеобразной ситуации в книге, чтобы она могла вам помочь.

Редактировать 2: На шагах 4 и 5 вашего цикла, если вы уже загрузили страну, нет необходимости активно загружать ее состояния, поскольку они уже должны быть загружены. Это разрывает бесконечный цикл.

1 голос
/ 29 июля 2009

Datamapper должен перехватывать циклические ссылки. Это доморощенный сборщик данных?

0 голосов
/ 30 июля 2009

Я просто хотел опубликовать решение, которое придумал, однако я верю, что есть много способов снять шкуру с этой кошки.

Вот мой FetchDepthCounterClass, который я создал:

public static class FetchDepthCounter
{
    private static Dictionary<Type, int> _DepthCounter;
    private static int _MaxDepth = 3;

    static FetchDepthCounter()
    {   
        _DepthCounter = new Dictionary<Type, int>();
    }

    public static void SetDepth(int depth)
    {
        _MaxDepth = depth;
    }

    public static void ResetCounter()
    {
        _DepthCounter.Clear();
    }

    public static bool IncrementCounter(Type entityType)
    {
        if(!_DepthCounter.ContainsKey(entityType))
        {
            _DepthCounter.Add(entityType, 0);
            return true;
        }

        if(_DepthCounter[entityType] < _MaxDepth)
        {
            ++_DepthCounter[entityType];
            return true;
        }

        return false;
    }

}

IncrementCounter возвращает логическое значение, указывающее, достигнута ли максимальная глубина выборки или нет. Я вызываю инкрементный счетчик как часть моего процесса отображения прямо перед тем, как установить значение свойства. Сначала я определяю, что мне нужно загрузить другой объект DTO или коллекцию DTO, и я передаю тип parent и приращение для этого типа. Вот небольшой кусочек кода внутри моего метода SetValue в моем datamapper:

if(isDto)
{
    if (!FetchDepthCounter.IncrementCounter(property.ComponentType))
        return;
}

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

...