Вопрос

Попытка сделать действительно простой модернизированный и сервисный слой. (.NET 4, C #, LINQ, хотя этот вопрос является частично языком-агностическим). Примечание: это просто R & D.

Моя цель состоит в том, чтобы минимизировать объем определений метода в моем сервисном слое.

Вот мой договор о репозитории:

interface IFooRepository
{
   IEnumerable<Foo> Find();
   void Insert(Foo foo);
   void Update(Foo foo);
   void Delete(Foo foo);
}

Ничего нового там.

Теперь, вот что я (пытаясь) иметь в моем договоре обслуживания:

interface IFooDataService
{
   public IEnumerable<Foo> Find(FooSearchArgs searchArgs);
}

По сути, любой конкретный «Foo» имеет много свойств (ID, имя, и т. Д.), Которые я хотел бы иметь возможность искать.

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

«FOOSEARCHARGS» - это просто простой Poco со всеми разными свойствами «FO».

Итак, это то, что я пытаюсь сделать, вот мои вопросы:

  • Это плохой дизайн? Если это так, каковы альтернативы?
  • Как я могу реализовать эту фильтрацию в сервисном слое? Если бы я должен проверить, какие свойства «FOOSearchargs» устанавливаются, затем продолжайте фильтрацию? (Если это, то запрос. Где, если это, Query.where, и т. Д.) У кого-то есть идея умного метода расширения Ienumerable Linq? (то есть repository.WhereMeetsSearchCriteria(fooSearchArgs))

Цените помощь.

Это было полезно?

Решение

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

Преимущество возврата IQueryable является то, что вы можете дополнительно уточнить ваши критерии за пределами вашего слоя репозитория.

repository.Find(predicate).Where(x => x.SomeValue == 1);

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

Мои личные предпочтения состоит в том, чтобы использовать шаблон спецификации, в котором вы передаваете свой метод нахождения. Объект ISPecification используется для выполнения запроса.

public interface ISpecification<TCandidate>
{
    IQueryable<TCandidate> GetSatisfyingElements(IQueryable<TCandidate> source);
}

public class TestSpecification : ISpecification<TestEntity>
{
    public IQueryable<TestEntity> GetSatisfyingElements(IQueryable<TestEntity> source)
    {
        return source.Where(x => x.SomeValue == 2);
    }
}

public class ActiveRecordFooRepository: IFooRepository
{
    ...

    public IEnumerable<TEntity> Find<TEntity>(ISpecification<TEntity> specification) where TEntity : class 
    {
        ...

        return specification.GetSatisfyingElements(ActiveRecordLinq.AsQueryable<TEntity>()).ToArray();

        ...
    }

    public TEntity FindFirst<TEntity>(ISpecification<TEntity> specification) where TEntity : class 
    {
        return specification.GetSatisfyingElements(ActiveRecordLinq.AsQueryable<TEntity>()).First();
    }
}

После того, как запрос запустит репозиторий, вызовы вызовы наличие или Tolist в результате IQueryable возвращаются из спецификации, чтобы запрос был оценен там, а затем. В то время как это может показаться менее гибким, чем разоблачение iQueryable, он поставляется с несколькими преимуществами.

  1. Запросы выполняются сразу и предотвращает вызов базы данных, сделанную после закрытия сеансов.
  2. Поскольку ваши запросы теперь связаны с техническими характеристиками, которые они являются благами.
  3. Технические характеристики являются многократными, означающие, что у вас нет дублирования кода при попытке запуска подобных запросах и любых ошибках в запросах нужно только закрепить в одном месте.
  4. С правильным видом реализации вы также можете объединить ваши спецификации вместе.

repository.Find(
    firstSpecification
        .And(secondSpecification)
        .Or(thirdSpecification)
        .OrderBy(orderBySpecification));

Другие советы

Проходит А. Функция В качестве параметра к методу поиска вашего сервиса, вместо FOOSearchArgs, опция? Перечислители имеют метод где (LINQ), который принимает функцию в качестве параметра, поэтому вы можете использовать его для фильтрации результатов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top