Функциональность поиска с использованием шаблона GenericRepository и SearchService - PullRequest
0 голосов
/ 25 апреля 2011

Я использую шаблон универсального репозитория для абстрагирования моего EF 4.1 DbContext.Я также использую сервисный уровень для запроса и фиксации изменений в репозитории.В любом случае, я пытаюсь добиться того, чтобы пользователь ввел поисковую фразу в строку поиска.Затем SearchService должен выполнить запрос к базе данных, чтобы найти любые категории, подкатегории или элементы TopLevel, которые содержат поисковую фразу в своих именах.На первый взгляд, я подумал, что это будет просто, но, видимо, все немного сложнее.Вот что я пытался сделать:

    public IList<Item> Search(string searchPhrase)
    {
        var result = new List<Item>();

        var tmp = from c in _repository.GetQuery<TopLevelCategory>(c=>c.Children)
                  where c.Name.Contains(searchPhrase)
                  select c;
        if(tmp.Count() > 0)
        {
            foreach (var c in tmp)
            {
                var children = c.Children;
                foreach (var childCategory in children)
                {
                    result.Concat(childCategory.Items);
                }
            }
        }

        var tmp2 = from c in _repository.GetQuery<ChildCategory>(c=>c.Items)
              where c.Name.Contains(searchPhrase)
              select c;
        if(tmp.Count() > 0)
        {
            foreach (var childCategory in tmp2)
            {
                result.Concat(childCategory.Items);
            }
        }

        var tmp3 = from c in _repository.GetQuery<Item>()
                   where c.Title.Contains(searchPhrase)
                   select c;
        if(tmp3.Count() > 0)
        {
            result.Concat(tmp3);
        }
        return result;
    }
}

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

Сведения об исключении: System.InvalidOperationException: уже существует открытый DataReader, связанный с этой командой, который должен быть закрыт первым.

Source:

Line 31:          foreach (var childCategory in children)
Line 32:          {
Line 33:                 result.Concat(childCategory.Items);
Line 34:          }

Так или иначе, должен быть более разумный способ сделать это ... Любые предложения?

Ответы [ 2 ]

2 голосов
/ 25 апреля 2011

Исключение говорит вам, что вы открыли DataReader для загрузки категорий верхнего уровня с их дочерними элементами, но вы запускаете отложенную загрузку во внутреннем цикле foreach.Для этого требуется другой DataReader, чтобы открывать и читать лениво загруженные элементы:

// Iterate top level categories => fist openned DataReader
foreach (var c in tmp)
{
    // Child category is eager loaded
    var children = c.Children;
    foreach (var childCategory in children)
    {
        // Items are not eager loaded => trigger lazy loading and open new DataReader
        result.Concat(childCategory.Items);
    }
}

Для решения этой проблемы необходимо изменить строку подключения и добавить поддержку MARS MultipleActiveResultSets=true.MARS поддерживается, по крайней мере, в SQL Server 2005 и 2008. Другой способ избежать этого - также стремление загружать элементы.

Это больше похоже на задачу для полнотекстового поиска на уровне базы данных.

0 голосов
/ 25 апреля 2011

Ошибка, которую вы получаете, может быть из-за MARS.Вам просто нужно включить несколько активных наборов результатов (MARS), просто добавьте 'MultipleActiveResultSets = True' в строку подключения.Отметьте здесь


  1. Вы можете создать представление, объединяющее имена в TopLevel, Childlevel и элементах.Затем представьте это представление как сущность.Помните, что у EF будут проблемы с представлениями, так как его разработчик попытался определить поле идентификатора.
  2. Вы можете посмотреть lucene , если считаете, что вам нужны более совершенные \ надежные возможности запросов.
...