Linq to SQL Repository ~ теория ~ - общая, но теперь использует Linq to Objects? - PullRequest
3 голосов
/ 16 ноября 2011

В проекте, над которым я сейчас работаю, Linq to SQL используется в качестве технологии доступа к данным ORM. Это веб-приложение MVC3. Проблема, с которой я столкнулся, была связана, прежде всего, с невозможностью моделирования (для тестирования) DataContext, который автоматически создается конструктором DBML.

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

[Редактировать: Для этого я использовал ссылку, предоставленную Джейкобом ниже, по совпадению!]

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

1) Рефакторинг кода, который использовал классические запросы Linq to SQL:

    public Billing GetBilling(int id)
    {
        var result = (
        from bil in _bicDc.Billings
        where bil.BillingId == id
        select bil).SingleOrDefault();
        return (result);
    }

теперь это выглядит так:

    public T GetRecordWhere<T>(Expression<Func<T, bool>> predicate) where T : class
    {
        T result;
        try
        {
            result = _dataContext.GetTable<T>().Where(predicate).SingleOrDefault();
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return result;
    }

и используется контроллером с запросом в следующих строках:

_repository.GetRecordWhere<Billing>(x => x.BillingId == 1);

что хорошо, и именно то, чего я хотел достичь.

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

viewModel.RecentRequests = _model.GetAllRecordsWhere<Billing>(x => x.BillingId == 1)
                .Where(x => x.BillingId == Convert.ToInt32(BillingType.Submitted))
                .OrderByDescending(x => x.DateCreated).
                Take(5).ToList();

Это - насколько я понимаю, правильно - теперь использует Linq to Objects, а не запросы Linq to SQL, которыми я был ранее? Это хорошая практика? Мне кажется, что это неправильно, но я не знаю почему. Вероятно, потому что логика запросов находится на самом высоком уровне приложения, а не на самом низком, но ... Я обращаюсь к вам, хорошие люди за советом. Одна из проблем, которую я рассмотрел, заключалась в переносе всей таблицы в память, но я понимаю, что при использовании возвращаемого типа Iqeryable предложение where переносится в базу данных и там оценивается. Таким образом, возвращая только тот набор результатов, который мне требуется ... я могу ошибаться.

И если вы сделали это далеко, молодец. Спасибо, и если у вас есть какие-либо советы, это очень ценится!

Обновление: включение метода GetAllRecordsWhere в соответствии с запросом

    public IQueryable<T> GetAllRecordsWhere<T>(Expression<Func<T, bool>> predicate) where T : class
    {
        return _dataContext.GetTable<T>().Where(predicate);
    }

, который использует:

    public IQueryable<TName> GetTable<TName>() where TName : class
    {
        return _db.GetTable<TName>().AsQueryable();
    }

Ответы [ 3 ]

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

Если _model.GetAllRecordsWhere возвращает IQueryable, то ваши последующие запросы все еще просто создают дерево выражений (что, я думаю, вы подразумеваете под использованием LinqToSql), оно превращается в SQL, выполняемый только тогда, когда вы перечисляете коллекцию путем итерации через него или вызов ToList () или ToArray ().

В сторону не делайте этого:

catch (Exception ex)
{
    throw ex;
}

Все, что вы делаете, - глотаете трассировку стека. Если вы хотите сбросить исключение, просто позвоните throw, а не throw ex. Если вы ничего не делаете в своем улове, кроме rethrow, то не поймайте. Нормальный шаблон для этого будет поймать, сделать некоторые записи, перебросить.

0 голосов
/ 16 ноября 2011

Вот хорошая статья, которая объясняет, как макетировать ваш DataContext:

Подделка вашего провайдера LINQ, часть 1

0 голосов
/ 16 ноября 2011

Если вы хотите смоделировать контекст базы данных, посмотрите это:

http://andrewtokeley.net/archive/2008/07/06/mocking-linq-to-sql-datacontext.aspx

...