In this video, Nate shows you how to build a search expression dynamically based on the parameters provided by the client.
- [Instructor] In order to use the search terms from the client in our database queries, we need to implement the apply method in the search options class. Typically, you'd use the link Where method to add a search term to a database query. So we might say something like, where name equals Oxford Suite. This only works, however, if you know the search terms at compile time. In our case, we need to dynamically build the link expression depending on the parameters in the incoming request. To keep the search options class light, we'll delegate this responsibility to the SearchOptionsProcessor as well.
We'll create a new SearchOptionsProcessor for this resource and entity type, pass in the parameters, and then just return processor.Apply. Passing in the query. So now we have to go implement the apply method on the SearchOptionsProcessor. This method will return an IQueryable of TEntity, and it will accept an IQueryable of TEntity. As we discussed when we were building the SortOptionsProcessor, it's important to use IQueryable here and not something else like INumerable.
IQueryable keeps track of the expression tree that eventually gets converted into a SQL statement or other database query. We can add our own expressions to the IQueryable expression tree with some code here. First we'll get all the valid terms from the current request and put those into an array. We can do a quick sanity check to make sure there are any terms, if not, we can reflect the query back exactly how it is with no additional processing needed. I'll create a local variable here to keep track of the modifiedQuery that will eventually return at the end.
And now we need to loop over all of the terms. For each term, we need to get a reference to the property info of the property it references on the model. We can use the ExpressionHelper code that I added in the sort chapter to do this. If you haven't gone through the sort chapter yet, you can pull this ExpressionHelper code out of the exercise files for this video. Next, we need a reference to the entity model that we're going to be acting on. This will be a parameter expression of type TEntity.
What we're going to do is build up the link expression backwards. Ultimately, what we need to do is something like query = query.Where, x lambda, x.Property equals Value. The first thing we need is the left side of this comparison, so x.Property, so we'll call this left, and this will be an expression of type PropertyExpression, referencing the object and the property info.
And now we need the right side, which is just the value, and we'll say var right = Expression.Constant, we'll need to import the ExpressionClass, and this is simply the term value. Now we can build the comparison, which is x.Property == Value. So we can say Expression.Equal to create an equality expression between left and right. We're almost there, now we can create the lambda, which is x lambda, x.Property == Value.
So the lambda expression will be ExpressionHelper.GetLambda of type TEntity, and since this is a predicate, it returns a bool on the object and the comparison expression. All right so now that we've built up the entire expression, now we just have to call it, so this is the query = query.Where part, we'll say the modifiedQuery is equal to ExpressionHelper.CallWhere, passing in the modifiedQuery, and the lambda. And after we're done with the entire loop, looping over any and all terms that we have in the term list, we'll just return the modifiedQuery.
All right, that should do it, let's try it out. If I make a request to the rooms route, and specify name equals Oxford Suite, I should only see one room in the result list. And it worked, let's try another search, we'll say name equals the Driscoll Suite. And we should get the other one. We search for an unknown room, we should get no results, so we know the search is working. Let's try searching on a different type, like the rate. Rate equals 101.19.
This time we get an error because we're trying to search on a number, but our expression code is adding a string to the comparison expression. We'll add some additional logic to handle other types, like numbers, next.
- REST vs. RPC
- Using HTTP methods (aka verbs)
- Returning JSON
- Creating a new API project
- Building a root controller
- Routing to controllers with templates
- Requiring HTTPS for security
- Creating resources and data models
- Returning data and resources from a controller
- Representing links (HREFs)
- Representing collections
- Sorting and searching collections
- Creating forms
- Caching and compression
- Authentication and authorization for RESTful APIs