Это скорее академическое любопытство, но я пытаюсь понять, как лучше всего выполнить следующее.
Представьте ситуацию, когда у вас есть объект 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 Capable (например, 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, Plain Old SQL.
Но он просто воняет "Написание собственного языка запросов", потому что вам нужно учитывать все возможные запросы, которые потребитель может захотеть сделать. например Возраст >= 18 && Возраст <= 65 && Имя LIKE '% John%'
Вариант 3.
Есть ли другие варианты?