user2859298
user2859298

Reputation: 1443

Linq search a list and a linked property

I have a list of Books, each book has a linked Author. My Api allows a user to search either by Title or Author.

In the Api i have a search Model

public class SearchOptions
{
    public string Title { get; set; }
    public string Author { get; set; }
}

The user may use both fields or just Title or just Author.

Here are my my Books and Author Models

public class Book
{        
    public string Title { get; set; }
    public string Description { get; set; }
    public Author LinkedAuthor { get; set; }      
}

public class AuthorEntity
{
        public string FirstName { get; set; }
        public string LastName { get; set; }
}

I've created the following Linq query but its not quite right because when the author is not completed i.e. it's a blank string i get all the results back.

I almost want to say if the string is not null or empty then apply the filter for author (and the same with the title) but I'm not sure how to do this in Linq?

var returnedBooks = _bookRepository.GetAll()
            .Where(x => x.Title.Contains(title) ||
            (x.LinkedAuthor.FirstName + " " + x.LinkedAuthor.LastName).Contains(authorName)).ToList();

Upvotes: 0

Views: 538

Answers (3)

Farhad Jabiyev
Farhad Jabiyev

Reputation: 26645

You can create where part of the query by checking values of the properties one by one. If user entered any title, then add filter for this property. If user entered name of the author, then add filter and so on...

var books = _bookRepository.GetAll();

if (!String.IsNullOrEmpty(title))
    books = books.Where(x => x.Title.Contains(title));

if (!String.IsNullOrEmpty(authorName))
{
    books = books.Where(x => x.LinkedAuthor.FirstName.Contains(authorName) || x.LinkedAuthor.LastName.Contains(authorName));
}

Upvotes: 2

Balagurunathan Marimuthu
Balagurunathan Marimuthu

Reputation: 2978

var returnedBooks = 
       from a in _bookRepository.GetAll() 
       where (
                  a.Title.Contains(title)) || 
                  ((a.LinkedAuthor.FirstName + " " + a.LinkedAuthor.LastName) != null 
                  && (a.LinkedAuthor.FirstName + " " + a.LinkedAuthor.LastName).Contains(authorName)
               ) 
         select a)
         .ToList();

Upvotes: 0

Razvan Dumitru
Razvan Dumitru

Reputation: 12452

You can check each query term and construct where clause based on them.

I assume you receive a request model - SearchOptions (with your query terms) : searchOptions

var books = _bookRepository.GetAll();

if (!string.IsNullOrEmpty(searchOptions.Title))
    books = books.Where(x.Title.Contains(searchOptions.Title));

if (!string.IsNullOrEmpty(searchOptions.AuthorName))
    books = books.Where((x.LinkedAuthor.FirstName + " " + x.LinkedAuthor.LastName).Contains(searchOptions.AuthorName));

Also make sure that you implement a method in your repository _bookRepository.GetQueryable() returning IQueryable for this type of constructed where clauses.

And what you'll implement then is the following:

var query = _bookRepository.GetQueryable();

if (!string.IsNullOrEmpty(searchOptions.Title))
   query = query.Where(x.Title.Contains(searchOptions.Title));

if (!string.IsNullOrEmpty(searchOptions.AuthorName))
   query = query.Where((x.LinkedAuthor.FirstName + " " + x.LinkedAuthor.LastName).Contains(searchOptions.AuthorName));

var books = query.ToList(); // or i don't know, just enumerate 

You can read more here: https://softwareengineering.stackexchange.com/questions/192044/should-repositories-return-iqueryable

And one more reference for dynamic where clauses: How do I implement a dynamic 'where' clause in LINQ?

Upvotes: 0

Related Questions