-1

I'm implementing a basic search service, and several different repositories are injected into it. The repositories have a method that allows for an expression to be used like so:

    public IEnumerable<T> Select(Expression<Func<T, bool>> predicate)
    {
        return _dbSet.Where(predicate).AsEnumerable().ToList();
    }

I currently have a statement like this in my search service:

        searchResult.FoundCustomers = _customerRepository.Select(x =>
            x.FirstName.StartsWith(searchString) ||
            x.LastName.StartsWith(searchString) ||
            x.City.StartsWith(searchString) ||
            x.Country.StartsWith(searchString) ||
            x.Phone.StartsWith(searchString) || x.Phone.EndsWith(searchString)).ToList();

Is there a way of improving the LINQ? The repetitiveness of searchString seems unnecessary, but I don't yet know LINQ well enough to know if there is a way of avoiding it.

user9993
  • 5,833
  • 11
  • 56
  • 117

2 Answers2

0

To your direct question: no, you need to compare the searchString with each field you wish to include in your search. However, there are ways to improve the experience of users of the repositories.

For example, you could implement a search method in your repository, then in your user code you would only need to invoke that method. You could also include an optional predicate in cases you wish to further filter the results as you do now:

public IEnumerable<T> Search( string searchString, Expression<Func<T, bool>> predicate )
{
    var query = _dbSet.Where( x =>
        x.FirstName.StartsWith( searchString ) ||
        // ...
        x.Phone.EndsWith( searchString ) );

    if( null != predicate )
    {
        query = query.Where( predicate );
    }

    return query.ToList();
}

Usage:

var searchResults = _customerRepository.Search( searchString );

You could also attribute searchable fields with custom attributes, then use those attributes to dynamically create the query. This takes some work up front (the implementation of which is better left to another question), but can be done in a generic manner so that all your repositories would benefit from it.

Usage example:

public class Customer
{
    [SearchField( Mode = SearchMode.StartsWith )]
    public string FirstName { get; set; }

    public string DontSearchMe { get; set; }

    [SearchField( Mode = SearchMode.StartsWith | SearchMode.EndsWith )]
    public string Phone { get; set; }
}

public abstract class Repository<T>
{
    public IEnumerable<T> Search( string searchString )
    {
        var predicate = //generate predicate from attributed properties on class T and searchString parameter

        return _context.Set<T>().Where( predicate ).ToList();
    }
}
Moho
  • 15,457
  • 1
  • 30
  • 31
0

Yes, you can use like this

Func<YourModel, bool> Expression;
Expression = x => x.Value == 1;

return _repo.Where(Expression));
Caner
  • 813
  • 1
  • 12
  • 26