C # Linq where the sentence is according to the property name

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; } } 

In addition, I have the following method, and I access personal data through the 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 get two parameters for the method: searchField and searchTerm .

searchField is for the name of the field whose value will be used for filtering. searchTerm is the value that will be used to compare with the return value (sorry if I don't understand here, but this is the most I can think of)

What I usually 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 perfectly. But if I make changes to my class, this code will have changes to break or to be in the absence of some functions if I add new properties to this class.

I am looking for something like below:

NOTE.

This code below is entirely in my imagination, and there is no such thing.

 model = model.Where(x => x.GetPropertyByName(searchField) == searchTerm); 

Am I flying too high here if this is not possible or is a complete idiot, if there is already a built-in way for this?

+6
source share
7 answers

I use this extension method to achieve what I want.

 public static IQueryable<TEntity> Where<TEntity>(this IQueryable<TEntity> source, string propertyName, string value) { Expression<Func<TEntity, bool>> whereExpression = x => x.GetType().InvokeMember(propertyName, BindingFlags.GetProperty, null, x, null).ObjectToString().IndexOf(value, StringComparison.InvariantCultureIgnoreCase) >= 0; return source.Where(whereExpression); } 

Note: ObjectToString is another extension method that returns string.Empty if the object passed to NULL

+2
source

For linq2Object, you can use reflection as shown below (this is not very fast):

 model.Where(x => x.GetType().GetProperty(propName).GetValue(x, null) == propVal); 

but for linq2Entity, I think this does not work, it works for linq2 objects.

+2
source

This should be type safe:

 public IEnumerable<T> Where<T,U>(Func<T,U> propertySelector, U value) { return model.Where(x => propertySelector(x) == value); } 

using:

 Where((MyClass x) => x.PropertyName, propertyValue); 

Or:

 public IEnumerable<T> Where<T>(Func<T,bool> entitySelector) { return model.Where(entitySelector); } 

using:

 Where<MyClass>(x => x.PropertyName == propertyValue && x.OtherProperty == otherValue); 
+1
source

I think the next implementation looks very similar to what you originally planned, although changing it to a general method probably makes more sense.

 public IEnumerable<Person> getPeople(string searchField, string searchTerm) { PropertyInfo getter=typeof(Person).GetProperty(searchField); if(getter==null) { throw new ArgumentOutOfRangeException("searchField"); } return _repo.GetAll().Where(x => getter.GetValue(x, null).ToString()==searchTerm); } 
+1
source

Use reflection

 model = model.Where(x => ((string)x.GetType().GetProperty("searchField").GetValue(0, null)) == searchTerm); 
0
source

Instead of using reflection functions, custom expression trees, etc. when using the Entity Framework, consider using Builder method extensions for standard LINQ statements that take strings rather than lambdas. They are much easier to build for dynamic query requirements:

  string filter = String.Format("it.{0} = @value", fieldName); var model = context.People.Where(filter, new ObjectParameter("value", searchValue)); 

Of course, this would mean that you need to modify your repository to return an IObjectSet, not an IEnumerable. It will work better. By returning IEnumerable, you moisten every row in your database in your repository, and then filter through LINQ for the objects, rather than applying the filter back to your database.

For more information about Builder methods in EF, see BuilderMethodSamples.cs at http://archive.msdn.microsoft.com/EFQuerySamples/Release/ProjectReleases.aspx?ReleaseId=4422 .

0
source

Source: https://habr.com/ru/post/899055/


All Articles