我可以在LINQ Where子句中使用属性吗?

时间:2019-04-18 21:41:11

标签: c# linq razor-pages

首先,对于这个标题是垃圾邮件,我深表歉意。我是C#和ASP的新手,我什至不知道如何问这个问题。

我正在尝试将搜索功能整合到我的网页中。我有一个文本框,其中包含用户想要的搜索词。下拉列表将选择要在数据库表中搜索的字段。因此,如果有姓和名,用户可以选择要搜索的名字。我有一个名为SearchField {get;的属性。 set;},它将保留用户在下拉菜单中选择的值,但是当我尝试在LINQ语句中将其与Contains(blah)一起使用时,出现错误。

由于我对C#真的一无所知,甚至错误告诉我什么,所以我做了很少的尝试。

cshtml文件

<form>
    <p>
        <select asp-for="SearchField" class="form-control">
            <option value="FirstName">First Name</option>
            <option value="LastName">Last Name</option>
            <option value="Salary">Salary</option>
            <option value="Gender">Gender</option>
            <option value="Department">Department</option>
            <option value="Location">Location</option>
            <option value="Performance">Performance</option>
        </select>
        Search: <input type="text" asp-for="SearchString" class="form-control" />
        <input type="submit" value="Filter" class="form-control" />
    </p>
</form>

cs文件

   [BindProperty(SupportsGet = true)]
   public string SearchField { get; set; }

   public async Task OnGetAsync()
    {
        var employees = from x in _context.Employee
                     select x;
        if (!string.IsNullOrEmpty(SearchString))
        {
            employees = employees.Where(x => x.SearchField.Contains(SearchString));
        }
        Employee = await employees.ToListAsync();
    }

错误:对象不包含“包含”的定义,并且最著名的扩展方法重载Queryable.Contains .....需要类型为IQueryable的接收器

2 个答案:

答案 0 :(得分:1)

您可以在C#中使用反射来获取基于SearchField的属性,并将该属性的值与SearchString进行比较。 https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/reflection

在您的情况下:

public async Task OnGetAsync()
    {
        var employees = from x in _context.Employee
                     select x;
        if (!string.IsNullOrEmpty(SearchString))
        {
            employees = employees.Where(x => x.GetType().GetProperty(SearchField).GetValue(x, null).ToString() == SearchString);
        }
        Employee = await employees.ToListAsync();
    }

您还可以通过以下方式使用String.Contains:

employees = employees.Where(x => x.GetType().GetProperty(SearchField).GetValue(x, null).ToString().Contains(SearchString, StringComparison.InvariantCultureIgnoreCase));

答案 1 :(得分:0)

您需要动态创建表达式树,该树将过滤表并仅返回匹配的值。

这是您需要的字符串属性(故意分布在多行上):

// Expression to construct: (Employee parameter) => parameter.GetPropertyValue(searchField).Contains(SearchValue)
var parameter = Expression.Parameter(typeof(Employee));
var employeePropertyValue = Expression.Property(parameter, searchField);

var constainsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var contains = Expression.Call(employeePropertyValue, containsMethod, Expression.Constant(searchString));
var whereCondition = (Expression<Func<Employee, bool>>)Expression.Lambda(contains, parameter);

// filtering
employees = employees.Where(whereCondition);

对于非字符串属性,您将需要根据属性类型构造不同的条件(例如,Enum属性将以整数形式存储在数据库中,因此您需要将SearchValue转换为Gender并使用Expression.Equal)