Интерфейсное решение
Если вы можете добавить интерфейс к вашему объекту, вы можете использовать его. Например, вы можете определить:
public interface IName
{
string Name { get; }
}
Тогда ваш репозиторий может быть объявлен как:
class Repository<T> where T:class, IName
{
public IQueryable<T> SearchExact(string keyword)
{
return db.GetTable<T>().Where(i => i.Name == keyword);
}
}
Альтернативное решение интерфейса
В качестве альтернативы вы можете поместить "where" в свой метод SearchExact, используя второй универсальный параметр:
class Repository<T> where T:class
{
public IQueryable<T> SearchExact<U>(string keyword) where U: T,IName
{
return db.GetTable<U>().Where(i => i.Name == keyword);
}
}
Это позволяет использовать класс Repository с объектами, которые не реализуют IName, тогда как метод SearchExact можно использовать только с объектами, которые реализуют IName.
Отражающий раствор
Если вы не можете добавить интерфейс, похожий на IName, к своим объектам, вы можете вместо этого использовать отражение:
class Repository<T> where T:class
{
static PropertyInfo _nameProperty = typeof(T).GetProperty("Name");
public IQueryable<T> SearchExact(string keyword)
{
return db.GetTable<T>().Where(i => (string)_nameProperty.GetValue(i) == keyword);
}
}
Это медленнее, чем использование интерфейса, но иногда это единственный способ.
Больше замечаний по интерфейсному решению и почему вы можете его использовать
В своем комментарии вы упоминаете, что не можете использовать интерфейс, но не объясняете почему. Вы говорите: «Ничего общего в трех моделях нет. Поэтому я думаю, что сделать интерфейс из них невозможно». Из вашего вопроса я понял, что все три модели имеют свойство «Имя». В этом случае можно реализовать интерфейс на всех трех. Просто реализуйте интерфейс, как показано, и ", IName" для каждого из ваших трех определений классов. Это даст вам наилучшую производительность как для локальных запросов, так и для генерации SQL.
Даже если рассматриваемые свойства не все называются «Name», вы все равно можете использовать решение nterface, добавив свойство «Name» к каждому и имея его метод получения и установки доступа к другому свойству.
Экспресс-решение
Если решение IName не будет работать и вам нужно преобразование SQL для работы, вы можете сделать это, создав запрос LINQ с помощью выражений. Это больше работы и значительно менее эффективно для локального использования, но хорошо конвертируется в SQL. Код будет примерно таким:
class Repository<T> where T:Class
{
public IQueryable<T> SearchExact(string keyword,
Expression<Func<T,string>> getNameExpression)
{
var param = Expression.Parameter(typeof(T), "i");
return db.GetTable<T>().Where(
Expression.Lambda<Func<T,bool>>(
Expression.Equal(
Expression.Invoke(
Expression.Constant(getNameExpression),
param),
Expression.Constant(keyword),
param));
}
}
и будет называться так:
repository.SearchExact("Text To Find", i => i.Name)