C # - How to make multiple contains filters in a list of objects

I have a datasheet that I am trying to do server side filtering for columns. I am allowing multiple rows to query per column and am trying to figure out the best way to go through all filters. Below is an example of a table object with two parameters for simplicity.

//table models from db
public class Parts
{
    public string PartName { get; set; }
    public virtual Series Series { get; set; }
}

public class Series
{
    public string SeriesName { get; set; }
}

//This is what is passed in from the datatable filter query
public class PartsTable
{
    public string PartName { get; set; }

    public string SeriesName { get; set; }
}


public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
    //Queries come in as comma separated string
    var partNameList = table.PartName?.Split(',');
    var seriesNameList = table.SeriesName?.Split(',');

    //Gets and generates the list of Parts
    var fullList = GetParts();

    if (partNameList != null && partNameList.Length > 0)
    {        
        foreach (var partName in partNameList)
        {
            fullList = fullList.Where(p => p.PartName.ToLower().Contains(name.ToLower()));
        }
    }
    if (seriesNameList != null && seriesNameList.Length > 0)
    {
        foreach (var seriesName in seriesNameList)
        {
            fullList = fullList.Where(p => p.Series.SeriesName.ToLower().Contains(seriesName.ToLower()));
        }
    }

    return fullList;
}

      

This won't work for what I want, because for each parameter (i.e. PartName) I need to return all objects named PartName containing search strings in partNameList, and then from this result filter further by SeriesNames, which contain search strings in the rowNameList, then return a result set. However, the query for partNameList can be empty and search only in serialName, and vice versa. Any suggestions? I feel like this is an obvious answer that I just ignore, although everything I was looking for only works for one request filter. Thanks in advance.

+3


source to share


4 answers


That's how I got the job.



var fullList = GetParts();        
if (partNameList != null && partNameList.Length > 0)
        {
            var tempList = new List<Parts>();
            foreach (var partName in partNameList)
            {
                tempList.AddRange(fullList.Where(p => p.PartName.ToLower().Contains(partName.ToLower().Trim())));
            }
            fullList = tempList;
        }
        if (seriesNameList != null && seriesNameList.Length > 0)
        {
            var tempList = new List<Parts>();
            foreach (var seriesName in seriesNameList)
            {
                tempList.AddRange(fullList.Where(p => p.Series.SeriesName.ToLower().Contains(seriesName.ToLower().Trim())).ToList());
            }
            fullList = tempList;
        }
return fullList.ToList();

      

0


source


This can be done with one in .Where

two ways:

Using.Contain()

which will return an exact match:

public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
    //Queries come in as comma separated string
    var partNameList = table.PartName?.Split(',');
    var seriesNameList = table.SeriesName?.Split(',');

    //Gets and generates the list of Parts
    var fullList = GetParts()
        .Where(p => partNameList.Contains(p.PartName.ToLower())
            || seriesNameList.Contains(p.Series.SeriesName.ToLower()))
        .ToList();

    return fullList;
}

      



Using.Any()

which will return a partial match:

public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
    //Queries come in as comma separated string
    var partNameList = table.PartName?.Split(',');
    var seriesNameList = table.SeriesName?.Split(',');

    //Gets and generates the list of Parts
    var fullList = GetParts()
        .Where(p => partNameList.Any(n => n.Contains(p.PartName.ToLower())))
            || seriesNameList.Any(n => n.Contains(p.Series.SeriesName.ToLower())))
        .ToList();

    return fullList;
}

      

+4


source


Made for LinqToSql. I was told that it would not work with Entity Framework. It should work with an in-memory collection.

    public static Expression<Func<T, bool>> OrTheseFiltersTogether<T>(
        this IEnumerable<Expression<Func<T, bool>>> filters)
    {
        Expression<Func<T, bool>> firstFilter = filters.FirstOrDefault();
        if (firstFilter == null)
        {
            Expression<Func<T, bool>> alwaysTrue = x => true;
            return alwaysTrue;
        }

        var body = firstFilter.Body;
        var param = firstFilter.Parameters.ToArray();
        foreach (var nextFilter in filters.Skip(1))
        {
            var nextBody = Expression.Invoke(nextFilter, param);
            body = Expression.OrElse(body, nextBody);
        }
        Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(body, param);
        return result;
    }

      

Called like this:

public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
    var fullList = GetParts();
    var filters = new List<Expression<Func<Part, bool>>>();

    if (table.PartName != null)
    {
        var partNameList = table.PartName.ToLower().Split(',');
        foreach (var partName in partNameList)
        {
            filters.Add(p => p.PartName.ToLower().Contains(partName));
        }
    }
    if (table.SeriesName != null)
    {
        var seriesNameList = table.SeriesName.ToLower().Split(',');
        foreach (var seriesName in seriesNameList)
        {
            filters.Add(p => p.Series.SeriesName.ToLower().Contains(seriesName));
        }
    }

    Expression<Func<Part, bool>> filter = filters.OrTheseFiltersTogether();

    return fullList.Where(filter);
}

      

0


source


Use Yield return

with every result set you get from different queries. It doesn't matter if it is null, all results will be collected in IEnumerable<Parts>

.

public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
    //Queries come in as comma separated string
    var partNameList = table.PartName?.Split(',');
    var seriesNameList = table.SeriesName?.Split(',');

    //Gets and generates the list of Parts
    var fullList = GetParts();

    if (partNameList != null && partNameList.Length > 0)
    {        
        foreach (var partName in partNameList)
        {
            yield return fullList.Where(p => p.PartName.ToLower().Contains(name.ToLower()));
        }
    }
    if (seriesNameList != null && seriesNameList.Length > 0)
    {
        foreach (var seriesName in seriesNameList)
        {
            yield return fullList.Where(p => p.Series.SeriesName.ToLower().Contains(seriesName.ToLower()));
        }
    }

  yield return null;
}

      

0


source







All Articles