Home > Software design >  C# - Parsing Data inside Lambda Linq Block | Splitting .Where()
C# - Parsing Data inside Lambda Linq Block | Splitting .Where()

Time:09-14

I want to filter Entities from a Database, but I am kinda stuck on how to correctly chain the Methods together....

The User can search from one Textfield the Id, Title and Description. This SearchString will be bound to SearchString in SearchData.

I have a method:

public List<Movies> Search(SearchData search)
{
    var movies = from m in entities select m;
    if (!String.isNullOrEmpty(search.SearchString))
    {
        movies = movies.Where(x => x.Title.Contains(search.SearchString)).Where(//descritpion);
    }
    return movies;
}

This works, but I also need to check for the Id

.Where(x=>x.Id == search.SearchString)

This won´t work since Id is a int and SearchString a String.

I have tried multiple ways to do so: I did use "Convert.ToInt32" on the SearchString or "Convert.ToString" on the Id, but out of some reason I won´t get anything back with this and an Error when I search for a String.

I tried to use a block with in the where : .Where(x => {if(Tryparse(Searchstring) {}else{}}), but it doesn´t like it when I try to return the Movie object or null.

I also tried to split the clause up:

if (int.tryparse(searchstring)) 
    movies = movies.where(x=>x.id ==Int32.Parse(SearchString));
movies = movies.where(//title and desc)

,but with this all the Movies I have found in the if will be filtered out due to the title and desc.

My questions are:

1.)Is it possible to "split" those Methods so that they behave like an OR instead of an AND?.... Or that they will not be executed anymore after one worked since the User will only be allowed to enter an Int OR a String. I have more values I am filtering against for which I would need this too.

2)How can I test against more "complex" Logic inside the Lambdas?

CodePudding user response:

I'm not sure if I understand it correctly but If you want to search where id == search.SearchString, and also any other condition with OR then you should do something like this:

.Where(x=>x.Id == search.SearchString && (x.description.Contains(search.Description) || x.Title.Contains(search.Title) || x.Whatever.Contains(search.Whatever)));

CodePudding user response:

You can use an OR in the Where clause.

public List<Movies> Search(SearchData search)
{
    var movies = from m in entities select m;
    if (!String.IsNullOrEmpty(search.SearchString))
    {
        movies = movies.Where(x => x.Title.Contains(search.SearchString) || x.Description.Contains(search.SearchString));
    }
    return movies;
}

CodePudding user response:

I don't understand why the movie Title should contain the movie Id, for my point of view it's bad practice,

i think you need to update the SearchData and add a separate field for the Id, and use it for filtering, this will make things more clear and easy for debugging

CodePudding user response:

In order to respect both conditions, I'd first check whether the search string can be parsed to an integer. If so, you can compare the id against it, if not, the Id comparison should be omitted:

public List<Movies> Search(SearchData search)
{
    var movies = from m in entities select m;
    if (!String.isNullOrEmpty(search.SearchString))
    {
        int? searchId;
        if (int.TryParse(search.SearchString, out i)
          searchId = i;
        else 
          searchId = null;
        movies = movies.Where(x => 
          (searchId.HasValue && x.Id == searchId.Value)
          || x.Title.Contains(search.SearchString)).Where(//descritpion);
    }
    return movies;
}

In the comparison, the first part checks whether the searchId is set and - if so - compares the id of the row against it. In addition, it checks whether the title contains the search string. If any of the two conditions are met, the row is returned. However, if the user enters 123 and this is both a valid id and part of a title, both rows will be returned.

If you want to search for id (exclusive) or a part of a text, you could use the following approach:

public List<Movies> Search(SearchData search)
{
    var movies = from m in entities select m;
    if (!String.isNullOrEmpty(search.SearchString))
    {
        Expression<Func<Movie, bool>> whereClause;
        if (int.TryParse(search.SearchString, out searchId)
          whereClause = (x) => x.Id == searchId;
        else 
          whereClause = (x) => x.Title.Contains(search.SearchString);
        movies = movies.Where(whereClause).Where(//descritpion);
    }
    return movies;
}

When entering 123, above sample searches for the id, when entering anything that cannot be parsed into an integer, it looks for a part of the title.

As for your second question: when using Entity Framework, the conditions in your lambda expressions are translated to SQL. This limits the available options. However, as shown in the first example, you can prepare your data and adjust the conditions accordingly in many cases. Nevertheless, not every valid lambda expression can be translated to SQL.

  • Related