Реализация универсальных методов для репозитория с использованием кода Entity Framework - PullRequest
1 голос
/ 23 ноября 2011

Я использую Entity Framework 4.1 и repository pattern.

Я пытаюсь создать методы, которые будут использоваться в большинстве сценариев. Я пытаюсь создать метод, который возвращает записи и сортирует их в соответствии с предоставленными критериями заказа. Можно отсортировать по 1, 2 или 3 столбцам. Я хочу, чтобы это было указано. Я нашел следующий код в Orchard framework.

В IRepository interface они имеют следующее (я оставил другие методы):

public interface IRepository<T>
{
     IEnumerable<T> Fetch(Expression<Func<T, bool>> predicate);
     IEnumerable<T> Fetch(Expression<Func<T, bool>> predicate, Action<Orderable<T>> order);
}

Реализация для IEnumerable<T> Fetch(Expression<Func<T, bool>> predicate, Action<Orderable<T>> order);:

public class Repository<T> : IRepository<T>
{
     public virtual IQueryable<T> Fetch(Expression<Func<T, bool>> predicate)
     {
          return Table.Where(predicate);
     }

     public virtual IQueryable<T> Fetch(Expression<Func<T, bool>> predicate, Action<Orderable<T>> order)
     {
          var orderable = new Orderable<T>(Fetch(predicate));
          order(orderable);
          return orderable.Queryable;
     }
}

Orderable class:

public class Orderable<T>
{
     private IQueryable<T> _queryable;

     public Orderable(IQueryable<T> enumerable)
     {
          _queryable = enumerable;
     }

     public IQueryable<T> Queryable
     {
          get { return _queryable; }
     }

     public Orderable<T> Asc<TKey>(Expression<Func<T, TKey>> keySelector)
     {
          _queryable = _queryable
               .OrderBy(keySelector);
          return this;
     }

     public Orderable<T> Asc<TKey1, TKey2>(Expression<Func<T, TKey1>> keySelector1,
          Expression<Func<T, TKey2>> keySelector2)
     {
          _queryable = _queryable
               .OrderBy(keySelector1)
               .OrderBy(keySelector2);
          return this;
     }

     public Orderable<T> Asc<TKey1, TKey2, TKey3>(Expression<Func<T, TKey1>> keySelector1,
          Expression<Func<T, TKey2>> keySelector2,
          Expression<Func<T, TKey3>> keySelector3)
     {
          _queryable = _queryable
               .OrderBy(keySelector1)
               .OrderBy(keySelector2)
               .OrderBy(keySelector3);
          return this;
     }

     public Orderable<T> Desc<TKey>(Expression<Func<T, TKey>> keySelector)
     {
          _queryable = _queryable
               .OrderByDescending(keySelector);
          return this;
     }

     public Orderable<T> Desc<TKey1, TKey2>(Expression<Func<T, TKey1>> keySelector1,
          Expression<Func<T, TKey2>> keySelector2)
     {
          _queryable = _queryable
               .OrderByDescending(keySelector1)
               .OrderByDescending(keySelector2);
          return this;
     }

     public Orderable<T> Desc<TKey1, TKey2, TKey3>(Expression<Func<T, TKey1>> keySelector1,
          Expression<Func<T, TKey2>> keySelector2,
          Expression<Func<T, TKey3>> keySelector3)
     {
          _queryable = _queryable
               .OrderByDescending(keySelector1)
               .OrderByDescending(keySelector2)
               .OrderByDescending(keySelector3);
          return this;
     }
}

Таким образом, способ, которым это можно использовать, будет следующим:

var foos = _fooRepos.Fetch(
     f => f.Name == "two" || f.Name == "three",
     o => o.Asc(f => f.Name, f => f.Id)
);

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

Ответы [ 3 ]

3 голосов
/ 23 ноября 2011

Я уверен, что у ребят из Orchard есть свои причины (они не смотрели на базу кода), но мне просто интересно, что это дает в таблице по сравнению с более «стандартным» решением на основе LINQ / IQueryable?

public interface IRepository<T>  
{  
    IQueryable<T> All(); 
} 

использование:

var foos = from f in _foosRepos.All()
           where f.Name == "two" || f.Name == "three"
           orderby f.Name, f.Id;

или

var foos = _foosRepos.All()
        .Where(f => f.Name == "two" || f.Name == "three")
        .OrderBy(f => f.Name).ThenBy(f => f.Id);
1 голос
/ 23 ноября 2011

См. Также реализацию универсального репозитория, которая позволяет вам указать критерии заказа в этом руководстве: http://www.asp.net/entity-framework/tutorials/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

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

Поскольку вы упоминаете, что элементы могут быть отсортированы по 1, 2 или 3 полям, вы можете расширить ответ jeroenh и "объединить" его с логикой из Orchard:

public interface IRepository<T>
{
    IQueryable<T> All();
    IQueryable<T> Sorted(Func<T, object> sort1, Func<T, object> sort2 = null, Func<T, object> sort3 = null);
}

public class Repository<T> : IRepository<T>
{
    public IQueryable<T> All()
    {
        // TODO: Implement real data retrieval
        return new List<T>().AsQueryable();
    }

    public IQueryable<T> Sorted(Func<T, object> sort1, Func<T, object> sort2 = null, Func<T, object> sort3 = null)
    {
        var list = All();

        var res = list.OrderBy(sort1);
        if (sort2 != null)
            res = res.ThenBy(sort2);
        if (sort3 != null)
            res = res.ThenBy(sort3);
        return res.AsQueryable();
    }
}
...