C# Linq where 子句根据属性名称
假设我有以下课程:
public class Person {
public string FirstName { get; set; }
public string SurName { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
}
另外,我有以下方法,并且我正在通过存储库访问人员数据。
public IEnumerable<Person> getPeople(string searchField, string searchTerm) {
//_repo.GetAll() returns IEnumerable<Person>
var model = _repo.GetAll();
//Need the logic here for filtering
return model;
}
正如您所看到的,我获得了该方法的两个参数:searchField
和 searchTerm
。
searchField
是其值将用于过滤的字段名称。 searchTerm
是用于与检索值进行比较的值(抱歉,如果我在这里不清楚,但这是我能想到的最多)
我通常会做什么做如下:
public IEnumerable<Person> getPeople(string searchField, string searchTerm) {
//_repo.GetAll() returns IEnumerable<Person>
var model = _repo.GetAll();
switch(searchField) {
case "FirstName":
model = model.Where(x => x.FirstName == searchTerm);
break;
case "SurName":
model = model.Where(x => x.SurName == searchTerm);
break;
//Keeps going
}
return model;
}
这会工作得很好。但是,如果我对我的类进行更改,则如果我在此类中添加新属性,则此代码将发生更改,从而破坏或缺少某些功能。
我正在寻找如下所示的内容:
注意:
下面的代码完全属于我的想象,没有这样的 事物存在。
model = model.Where(x => x.GetPropertyByName(searchField) == searchTerm);
如果这是不可能的,我是否在这里飞得太高了,或者如果已经有内置的方法来实现这一点,我是不是完全白痴?
Let's say I have the following class :
public class Person {
public string FirstName { get; set; }
public string SurName { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
}
Also, I have the following method and I am reaching out to person data via a repository.
public IEnumerable<Person> getPeople(string searchField, string searchTerm) {
//_repo.GetAll() returns IEnumerable<Person>
var model = _repo.GetAll();
//Need the logic here for filtering
return model;
}
As you can see I am getting two parameter for the method : searchField
and searchTerm
.
searchField
is for the field name whose value will be used for filtering. searchTerm
is the value which will be used to compare with retrived value (sorry if I am not clear here but this is the most I can come up with)
What I would normally do is as follows :
public IEnumerable<Person> getPeople(string searchField, string searchTerm) {
//_repo.GetAll() returns IEnumerable<Person>
var model = _repo.GetAll();
switch(searchField) {
case "FirstName":
model = model.Where(x => x.FirstName == searchTerm);
break;
case "SurName":
model = model.Where(x => x.SurName == searchTerm);
break;
//Keeps going
}
return model;
}
Which will work just fine. But if I make a change on my class, this code will have a change to break or be in lack of some functions if I add new properties this class.
What I am looking for is something like below :
NOTE :
This below code completely belongs to my imagination and there is no such a
thing exists.
model = model.Where(x => x.GetPropertyByName(searchField) == searchTerm);
Am I flying too high here if it is impossible or being complete idiot if there is already a built in way for this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
看起来您需要动态 Linq 查询:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Looks like you need Dynamic Linq queries:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
我使用这个扩展方法来实现你想要的。
注意:
ObjectToString
只是另一个扩展方法,如果传入的对象为NULL
,则返回 string.EmptyI use this extension method to achieve what you want.
Note:
ObjectToString
is just another extension method that returns string.Empty if the Object passed in isNULL
对于 linq2Object 您可以使用反射,如下所示(它不是很快):
但对于 linq2Entity 我认为这不起作用,它适用于 linq2objects。
For linq2Object You can use reflection as bellow(it's not very fast):
but for linq2Entity I think this doesn't work, it works for linq2objects.
我认为以下实现看起来非常像您最初的意图,尽管将其更改为通用方法可能更有意义。
I think the following implementation looks an awful lot like what you originally intended, although changing this to a generic method likely makes more sense.
使用反射
Use Reflection
这应该是类型安全的:
用法:
或:
用法:
This should be type-safe:
usage:
Or:
usage:
使用实体框架时,不要搞乱反射、自定义表达式树等,而是考虑使用标准 LINQ 运算符的生成器方法扩展,该运算符采用字符串而不是 lambda。这些对于动态查询要求来说更容易构建:
当然,这意味着您需要修改存储库以返回 IObjectSet 而不是 IEnumerable。它也会表现得更好。通过返回 IEnumerable,您可以将数据库中的每一行合并到存储库中,然后通过 LINQ to Objects 进行过滤,而不是将过滤器应用回数据库中。
有关 EF 中的生成器方法的详细信息,请参阅 http://archive.msdn.microsoft.com/EFQuerySamples/Release/ProjectReleases.aspx?ReleaseId=4422。
Rather than messing with reflection, custom expression trees, etc., when using Entity Framework, consider using the Builder Method extensions to the standard LINQ operators which take strings rather than lambdas. These are much easier to build for dynamic query requirements:
Of course, this would mean that you yould need to modify your repository to return IObjectSet rather than IEnumerable. It would perform better as well. By returning IEnumerable, you are hydrating every row in your database to your repository and then filtering via LINQ to Objects rather than applying the filter back in your database.
For more information about the Builder Methods in EF, see the BuilderMethodSamples.cs in http://archive.msdn.microsoft.com/EFQuerySamples/Release/ProjectReleases.aspx?ReleaseId=4422.