1

I have a simple Person View Model

public class PersonViewModel
{
    public int ID {get;set;}
    public String FirstName {get;set;}
    public String LastName {get;set;}
}

The view has three fields

form

I have this function in my PersonService which uses an EF6 datacontext which gets injected.

 public IQueryable<Person> Search(Expression<Func<Person,bool>> predicate)
        {
            return dataContext.GetSet<Person>().Where(predicate);
        }

Now my MVC Controller actually works with a PersonViewModel class

[HttpPost]
public ActionResult Search(PeopleSearchViewModel model)
{
      if (ModelState.IsValid)
            {
                var listOfPersons= PersonService.Search(
                   //map viewmodel to model and search here)

                //return the list and render a view etc...not important
            }
        }

So what I am wondering is whether it is a good idea if I can somehow take the PersonViewModel, create a Func<Person,bool> predicate and pass it to the PersonService for search, instead of using automapper to map my view model to domain model ?

Thanks

iAteABug_And_iLiked_it
  • 3,725
  • 9
  • 36
  • 75
  • It won't work normally because you send `Func<>` to `Where` method and then all filtration will be done on .Net side and the whole table will be loaded from DB that is bad. It should be `Expression>` – Sergey Litvinov Oct 26 '14 at 21:47
  • sorry I missed that , I have updated the code -- although I'm not sure if that is what you meant. – iAteABug_And_iLiked_it Oct 26 '14 at 21:52
  • Yeah, i meant it. Hm, `Search` method is used for filtering. It doesn't require real instance of `Person` class, so what is your problem? you want to use `PersonSearchViewModel` for `Search` filtering? – Sergey Litvinov Oct 26 '14 at 21:54

1 Answers1

2

Firstly, you are passing type Func as the predicate to a function returning an IQueryable. You should actually be passing in an Expression<Func<Person, bool>> so that whatever generates your query can actually inspect the function as an expression tree and generate SQL or something from it. If you don't, your query generator may end up loading your entire table and iterating manually (saw this happen with entity framework once).

On to your answer: I would make a function on your PeopleSearchViewModel like so:

public Expression<Func<Person, bool>> ToExpression()
{
    //this can be whatever your search query needs to be... I just did this quick and dirty
    return p => p.FirstName == this.FirstName || p.LastName == this.LastName  || p.ID == this.ID;
}

Then, simply pass the result of calling model.ToExpression() in to your search function.

Los Frijoles
  • 4,771
  • 5
  • 30
  • 49
  • +1 this look exactly like what i had in mind, but as I mentioned in the question, any obvious drawbacks to this that I am overlooking? – iAteABug_And_iLiked_it Oct 26 '14 at 21:57
  • It does require manual modification if your search model or person model changes, but you're going to have to deal with that anyway unless you end up using a mapper library of some sort. But that should be the only major problem... I use this pattern all the time – Los Frijoles Oct 26 '14 at 21:59
  • thanks... would it be unreasonable to try to create a generic version of this ToExpression function? or would i have to create one for each view model? – iAteABug_And_iLiked_it Oct 26 '14 at 22:29