Работа с запросами в шаблоне репозитория с несколькими конкретными реализациями?

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

Представьте себе ситуацию, когда у вас есть объект Person

public class Person {
    public string Name {get;set;}
    public int Age {get;set;}
}

и контракт репозитория для их извлечения из некоторого хранилища постоянных данных ...

public class IPersonRepository {
    public IEnumerable<Person> Search(*** SOME_METHOD_SIGNATURE ***);
}

Ваше потребительское приложение действительно не заботится о конкретной реализации . Он просто получит правильную конкретную реализацию из Unity / Ninject и начнет запросы.

IPersonRespository repo = GetConcreteImplementationFromConfig();
repo.Search( ... );

Что мне интересно, так это то, что вы бы использовали здесь для своей подписи метода, которая является гибкой и расширяемой независимо от реализации.

Вариант 1.

public IEnumerable<Person> Search(Expression<Func<Person, bool>> expression);

Это хорошо, потому что если вы используете контекст данных с поддержкой LINQ (например, EntityFramework), вы можете просто передать выражение непосредственно в свой контекст. Этот вариант, похоже, не работает, хотя, если ваша реализация должна использовать вручную созданные хранимые procs / sql / ADO.NET и т. Д.

Вариант 2.

public IEnumerable<Person> Search(PersonSearch parameters);

public class PersonSearch {
    public int? Age {get;set;}
    public string FullName {get;set;}
    public string PartialName { get; set; }
}

Этот вариант кажется наиболее гибким (в том смысле, что он будет работать как с Linq, так и с обычным старым SQL.

Но от этого просто воняет «написанием собственного языка запросов», потому что вам нужно учитывать каждый возможный запрос, который может захотеть выполнить потребитель, например Age> = 18 && Возраст <= 65 && Имя LIKE '% John%'

Вариант 3.

Есть ли другие варианты?

10
задан smartcaveman 13 November 2011 в 16:09
поделиться