您正在使用实体框架,它可以访问您的Persons 表。您可能会有一个 DbContext 具有访问此表的属性:
public DbSet<Person> Persons {get; set;}
你还有两个字符串。一个字符串表示要过滤的Person 属性的名称,另一个字符串表示该属性应具有的值。
为了让您的代码更易于阅读、更易于重用、更易于维护和单元测试,我的建议是将您的问题拆分为两个子问题:
- 将字符串
columnToSearch(实际上是您要搜索的列的名称)翻译成propertySelector,类似于GroupBy中的keySelector。
- 创建使用此 KeySelector 选择属性的扩展方法,并使用
searchTerm 和 Where 仅保留具有相同值的 Persons。
这种分离的好处是,您可以在访问数据库之前检测 columnToSearch 的错误值。如果您不想支持某些属性,例如外键,可以将它们排除在外。该方法易于理解、易于重用、易于单元测试并且易于更改,例如,如果您想添加一个新列。
Expression<Func<Person, string>> ToPropertySelector(string columnName)
{
switch (columName)
{
case nameof(Person.Name):
return person => person.Name;
case nameof(Person.FirstName):
return person => person.FirstName;
...
default: // unsupported columnName
throw new InvalidArgumentException(...);
}
}
如果您的列有其他名称而不是您想与用户交流的名称,例如,如果外部使用想到 LastName 而不是名称,您可以轻松更改过程:
case "Name":
case "LastName":
return person => person.Name;
此外,如果以后列名更改,外部用户也不必更改。
用法:
string columName = "Email";
string value = "MyName.Gmail.Com";
using (var dbContext = new MyDbContext(...))
{
var propertySelector = ToPropertySelector(columnName);
return dbContext.Persons
.Where(person => propertySelector(person) == value)
.ToList();
}
当然,这只有在你的属性有一个字符串作为值时才有效。如果您还想支持其他属性类型,则需要创建一个具有正确类型的扩展方法:
Expression<Func<Person, TProperty>> ToPropertySelector<TProperty>(string columnName)
{
... see above
}
public static IQueryable<Person> Where<TProperty>(IQueryable<Person> persons,
string columName,
TProperty value)
{
var propertySelector = ToPropertySelector<TProperty>(columnName);
return persons.Where(person => propertySelector(person) == value);
}
public static IQueryable<Person> Where<TProperty>(IQueryable<Person> persons,
string columName,
string valueTxt)
{
Type propertyType = typeof(TProperty);
TypeConverter converter = propertyType.GetConverter();
TProperty value = converter.ConvertFromString(valueTxt)
return persons.Where(columnName, value);
}
用法:
DateTime birthDay = new DateTime(1993, 11, 23);
IQueryable<Person> persons = ...
var personsBornOnDate = persons.Where("BirthDay", birthDay);
重用示例:不必将BirthDay用作字符串,可以使用属性选择器:
var personsBornOnDate = persons.Where(person => person.BirthDay, birthDay);
后者的好处是,如果您使用不存在的属性,编译器会警告您。字符串版本只会在运行时发出警告。