Подтвердить что ты не робот

Должны ли хранилища реализовать IQueryable <T>?

Я рассматриваю один из двух интерфейсов IRepository, один из которых является потомком IQueryable, и тот, который содержит IQueryable.

Вот так:

public interface IRepository<T> : IQueryable<T>
{
    T Save(T entity);
    void Delete(T entity);
}

Или это:

public interface IRepository<T>
{
    T Save(T entity);
    void Delete(T entity);
    IQueryable<T> Query();
}

Использование LINQ будет:

from dos
in ServiceLocator.Current.GetInstance<IRepository<DomainObject>>()
where dos.Id == id
select dos

Или...

from dos
in ServiceLocator.Current.GetInstance<IRepository<DomainObject>>().Query
where dos.Id == id
select dos

Мне нравится первый, но это проблематично издеваться. Как другие люди реализовали LINQable, mockingable repositories?

4b9b3361

Ответ 1

Зависит от того, хотите ли вы отношения Has-A или Is-A.

Первый - это отношение Is-A. Интерфейс IRepository - это интерфейс IQueryable. Второй - has-a. IRepository имеет интерфейс IQueryable. В процессе написания этого, мне на самом деле нравится второй лучше, чем первый, просто потому, что, когда вы используете свой второй IRepository, я могу передать метод Query() AnyYING, который возвращает IQueryable. Для меня это более гибкая, чем первая реализация.

Ответ 2

Лично я использую Repository Pattern для возврата всех элементов из репозитория в качестве IQueryable. Таким образом, мой слой репозитория теперь очень легкий, маленький.. со слоем обслуживания (который поглощает уровень репозитория) теперь можно открыть для всех типов манипуляций с запросами.

В принципе, вся моя логика теперь находится на уровне сервиса (который понятия не имеет, какой тип репозитория он будет использовать.. и не хочет знать < - разделение проблем), тогда как мой уровень репозитория просто занимается получением данных и сохранением данных в репо (сервер sql, файл, спутник в космосе.. и т.д. - большее разделение проблем).

например. Более или менее код pseduo, поскольку я помню, что мы сделали в нашем коде и упростили его для этого ответа...

public interface IRepository<T>
{
    IQueryable<T> Find();
    void Save(T entity);
    void Delete(T entity);
}

и иметь пользовательский репозиторий...

public class UserRepository : IRepository<User>
{
    public IQueryable<User> Find()
    {
        // Context is some Entity Framework context or 
        // Linq-to-Sql or NHib or an Xml file, etc...
        // I didn't bother adding this, to this example code.
        return context.Users().AsQueryable();
    }

    // ... etc
}

и теперь для лучшего бита:)

public void UserServices : IUserServices
{
    private readonly IRepository<User> _userRepository;

    public UserServices(IRepository<User> userRepository)
    {
        _userRepository = userRepository;
    }

    public User FindById(int userId)
    {
        return _userRepository.Find()
            .WithUserId(userId)
            .SingleOrDefault();  // <-- This will be null, if the 
                                 //     user doesn't exist
                                 //     in the repository.
    }

    // Note: some people might not want the FindBySingle method because this
    //       uber method can do that, also. But i wanted to show u the power
    //       of having the Repository return an IQuerable.
    public User FindSingle(Expression<Func<User, bool>> predicate)
    {
        return _userRepository
            .Find()
            .SingleOrDefault(predicate);
    }
}

Бонусные баллы: WTF WithUserId(userId) в методе FindById? Это Труба и фильтр. Используйте их:) любите их:) обнимайте их:) Они делают ваш код SOOO очень читаемым:) Теперь, если вы хотите узнать, что это делает... это метод расширения.

public static User WithId(this IQueryable<User> source, int userId)
{
    return source.Where(u => u.UserId == userId).SingleOrDefault();
}

HTH, хотя этот вопрос... ну... почти два года:)

Ответ 3

Вы всегда можете быстро писать материал против List, но не издеваться над фреймворком, но он отлично работает.