Написание динамических запросов LINQ как методов закрытия - PullRequest
0 голосов
/ 09 ноября 2011

Я пытаюсь написать репозиторий C # с атомарным контекстом и чувствую, что это идеальная ситуация для использования замыкания, но я не совсем понимаю, как это сделать в C #.У меня есть это как основной метод в моем хранилище:

...
    protected virtual IQueryable<T> AsQueryable()
    {
        return _context.ObjectSet<T>().AsQueryable();
    }
...

Между тем, я получил производные классы с методами, такими как:

...
    public IQueryable<Arc> ByRun(Run run)
    {
        IQueryable<Arc> query = from o in AsQueryable()
                                     from r in o.Runs
                                     where r.Id == run.Id
                                     select o;
        return query;
    }
...

, и я хочу изменить свой метод запроса, чтобы вернуть IEnumerableи быстро распоряжаться контекстом, поэтому вы хотите использовать (что-то вроде) это:

...
    protected virtual IEnumerable<T> AsEnumerable()
    {
        using (IContextUnitOfWork unitOfWork = new EFUnitOfWork())
        {
            return unitOfWork.ObjectSet<T>().ToList();
        }
    }
...

Проблема, конечно, заключается в том, что после удаления контекста вызов LINQ для полученного набора IEnumerable завершится неудачно.,Таким образом, я думаю, что я должен связать метод ByRun () и передать его в AsEnumerable () для использования в качестве замыкания.

Хотя я не использовал свой оригинальный стиль языка, я изучил замыкания в Ruby.Там то, что я пытаюсь сделать, выглядело бы примерно так: смешанный псевдокод:

ByRun(Run run)
  AsEnumerable do |query|
    from o in query
           from r in o.Runs
           where r.Id == run.Id
           select o;
  end
end

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

1 Ответ

1 голос
/ 09 ноября 2011

Если я правильно понимаю вопрос, вы хотите иметь оболочку для любого запроса, чтобы гарантировать, что AsEnumerable вызывается в конце и контекст удаляется сразу после запроса?

Если это так (при условии, что ваш базовый класс является общим для параметра T), попробуйте следующее:

protected virtual IEnumerable<T> AsEnumerable(Func<ObjectSet<T>, IQueryable<T>> query)
{
    using (IContextUnitOfWork unitOfWork = new EFUnitOfWork())
    {
        return query(unitOfWork.ObjectSet<T>()).AsEnumerable();
    }
}

И пример использования:

public IEnumerable<Arc> ByRun(Run run)
{
    return AsEnumerable(query => from o in query
                                 from r in o.Runs
                                 where r.Id == run.Id
                                 select o);
}

Параметр AsEnumerable здесь - это лямбда-выражение, содержащее любой делегат, который принимает ObjectSet<T> в качестве единственного параметра и возвращает IQueryable<T>. Таким образом, логически эквивалентно иметь следующий код в производном классе:

public IEnumerable<Arc> ByRun(Run run)
{
    using (IContextUnitOfWork unitOfWork = new EFUnitOfWork())
    {
        return (from o in unitOfWork.ObjectSet<T>()
                from r in o.Runs
                where r.Id == run.Id
                select o).AsEnumerable();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...