Prasad Kanaparthi
Prasad Kanaparthi

Reputation: 6563

How to ignore null properties in the search criteria

I have got a bad requirement to do; anyway I have to implement that in my application.

I have a Track class

public class Track
{
    public string Name { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
}

and i have some test data

List<Track> Records = new List<Track>
{ 
    new Track { City = "a", Name = "a",  Country = "i" }, // Track 1
    new Track { City = "b", Name = "b",  Country = "i" }, // Track 2
    new Track { City = "a", Name = null, Country = "J" }, // Track 3
    new Track { City = "c", Name = "a",  Country = "J" }, // Track 4
    new Track { City = "b", Name = "a",  Country = null}, // Track 5
};

Requirement is i should query the data from Records based on values passed. If any of the property is null then search criteria should ignore that property. It should query based on NonNull properties.

Example:

If i query for City = a, Name = "b", Country = "i" then Result is: Track 1 & Track 3
If i query for City = c, Name = "p", Country = "w" then Result is: Track 4

Name & Country have null values in Track 3 & Track 5.So it will ignore in search. Hope it is clear

I finally land up with below logic

var filterRecords = new List<Track>();
if (!Records.Any(t => string.IsNullOrWhiteSpace(t.City)))
{
    filterRecords = Records.Where(c => c.City == _city).ToList();  // Here _city is the method parameter.. assume "a"
}

if (!Records.Any(t => string.IsNullOrWhiteSpace(t.Country)))
{
    filterRecords = filterRecords.Where(c => c.City == _country).ToList();  // Here _country is the method parameter.. assume "c"
}

Track class has 12 properties. Checking for 12 times like above is not good sign. I would like to achieve this by using LINQ or any other which is simple.

Any suggestions please?.

Upvotes: 3

Views: 2559

Answers (5)

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236218

Best solution came to my mind is to build aggregate filter (You can use your Track object for that, because it already has all possible properties for filtering collection, and they are nullable):

Track filter = records.Aggregate(
    new Track() { City = _city, Country = _country, Name = _name },
    (f, t) => new Track()
    {
        City = String.IsNullOrEmpty(t.City) ? null : f.City, 
        Country = String.IsNullOrEmpty(t.Country) ? null : f.Country,
        Name = String.IsNullOrEmpty(t.Name) ? null : f.Name
    },
    f => f);

This will require only one iteration over collection to define which fields has null. Then simply apply filter to your records:

var query = from t in Records
            where (filter.City == null || t.City == filter.City) &&
                    (filter.Country == null || t.Country == filter.Country) &&
                    (filter.Name == null || t.Name == filter.Name)
            select t;

Upvotes: 6

JJschk
JJschk

Reputation: 431

something like this

var listRecords = from track in Records
where (track.city == _city && !string.IsEmpyOrNull(track.city)) && 
(track.Name== _name && !string.IsEmpyOrNull(track.Name))
select track;

and you can add the rest of the conditions

Upvotes: -1

bonCodigo
bonCodigo

Reputation: 14361

do the quality and quantity of results returned matter to you? I assume you have mechanisms to handle the quantity.

You can validate your search keywords before throwing queries. Do you only care about nulls? How about redundant keywords? I would consider: 1. validate keywords - 12 can be looped. 2. Build the search keyword strong 3. Shoot a query

Seems pretty straightforward, unless there's more to it than what you described here.

Please recorrect me, if my understanding of your question is not in the expected direction.

Upvotes: 0

Icemanind
Icemanind

Reputation: 48686

If I'm understanding, it should be this simple:

var results = Records.Select(p => p.City != null && 
              p.Country != null && 
              p.Name != null).ToList();

Upvotes: 0

Tejs
Tejs

Reputation: 41236

You can easily chain these expressions together to create something like the following. Enumerating the records X times is going to slow down your code. Example:

var actualResult = Records
       .Where(x => x.City == _city || string.IsNullOrEmpty(x.City))
       .Where(x => x.Country == _country || string.IsNullOrEmpty(x.Country))
       /// .... and so on
       .ToList()

Now, if you're looking to not just write 12 lines of code, there are more complicated solutions that involve Reflection and mapping, but that's not really needed in this situation. If your property count is huge, then maybe it might be worth it. But 12 properties is small enough that there isn't much code smell here to me.

Upvotes: 0

Related Questions