Junaid Akhtar
Junaid Akhtar

Reputation: 33

Search criteria on multiple properties c#

I want to perform search criteria on multiple properties but, I am having a problem. If some property is empty or null which is not part of search criteria please help me..here is the code below :

public List<AccountDto> getSearchedAccount(int accountid,int userid,String holdername,String type,double balance,String status)
{
    List<AccountDto> results = new List<AccountDto>();
    for (int i = 0; i < list.Count; i++)
    {
        AccountDto dto = (AccountDto)list[i];
        if ((dto.Accountid == accountid) && (dto.Userid==userid) && (dto.Holdername.Equals(holdername)) && (dto.Balance == balance) && (dto.Status.Equals(status)) )
        {
            results.Add(dto);
        }

    }

    return results;
}

Please tell me the correct if statement is some field is null or empty which doesn't come in search criteria.

Upvotes: 2

Views: 1956

Answers (6)

Ken Kin
Ken Kin

Reputation: 4693

/*** Answer with the comments in code ***/ 
// don't create a class to represent your criteria
// Dictionary is enough for use and supported by Linq
// don't use a lot of `&&` or `if`; one `if` is enough
// all the rules is in deferred execution, only executes when it really needs 
// evaluated and the order to put where clauses matters, don't make it changed
// it performs like short-circuit evaluation

/// <summary>
/// declared as partial for easily coexists with original code
/// if not used(e.g already declared) then not paste to file
/// </summary>
partial class AccountDto /* known members */ {
    public int Accountid;
    public int Userid;
    public String Holdername;
    public int Balance;
    public String Status;
}

/// <summary>
/// declared as partial for easily coexists with original code
/// if getSearchedAccount is declared with another class name
/// then just rename the partial class to that name and remove 
/// all `static`(if that class is non-static) 
/// the class initializer, then become constructor; remember to 
/// match the name of class and constructor
/// </summary>
partial class AccountDto {
    /// <summary>
    /// declare as static for this demo; 
    /// not necessarily be static if it's declared in another 
    /// class where list is declared
    /// </summary>
    public static List<AccountDto> getSearchedAccount(
        int accountid, int userid,
        String holdername, String type,
        double balance,
        String status
        ) {
        var results=new List<AccountDto>();

        // make a copy of IgnoreRules and clear; equivalent to 
        // var matchRules=new Dictionary<String, Func<AccountDto, bool>>();
        // IgnoreRules is not changed with these two statement
        // just prevent to see too many angle braces
        var matchRules=IgnoreRules.ToDictionary(x => x.Key, x => x.Value);
        matchRules.Clear();

        // the parameters only known in this method thus can only added here
        matchRules.Add("accountid", x => accountid==x.Accountid);
        matchRules.Add("userid", x => userid==x.Userid);
        matchRules.Add("holdername", x => holdername==x.Holdername);
        matchRules.Add("balance", x => balance==x.Balance);
        matchRules.Add("status", x => status==x.Status);

        for(int i=0; i<list.Count; i++) {
            var dto=(AccountDto)list[i];

            if((from ignoreRule in IgnoreRules
                from matchRule in matchRules
                where ignoreRule.Key==matchRule.Key
                where !ignoreRule.Value(dto)
                select matchRule.Value(dto)).All(x => x))
                results.Add(dto);
        }

        return results;
    }

    /// <summary>
    /// criteria for `don't test for matching`
    /// </summary>
    public static Dictionary<String, Func<AccountDto, bool>> IgnoreRules {
        get;
        set;
    }

    /// <summary>
    /// use class initializer to add common IgnoreRules
    /// </summary>
    static AccountDto() {
        IgnoreRules=new Dictionary<String, Func<AccountDto, bool>>();
        IgnoreRules.Add("accountid", x => 0==x.Accountid);
        IgnoreRules.Add("userid", x => 0==x.Userid);
        IgnoreRules.Add("holdername", x => String.IsNullOrEmpty(x.Holdername));
        IgnoreRules.Add("balance", x => 0==x.Balance);
        IgnoreRules.Add("status", x => String.IsNullOrEmpty(x.Status));
    }

    /// <summary>
    /// declare as static for this demo; 
    /// not necessarily be static if it's declared in another 
    /// class where getSearchedAccount is declared
    /// </summary>
    public static List<AccountDto> list=new List<AccountDto>();
}

Upvotes: 0

Chris Moutray
Chris Moutray

Reputation: 18379

I'd probably check against default(type) and string.IsNullOrEmpty(...)

So you would could have:

public List<AccountDto> getSearchedAccount(int accountid, int userid, string holdername, string type, double balance, string status)
{
    var results = new List<AccountDto>();

    for (int i = 0; i < list.Count; i++)
    {
        AccountDto dto = (AccountDto)list[i];

        if (accountid != default(int) && accountid != dto.Accountid)
            continue;
        if (userid != default(int) && userid != dto.Userid)
            continue;
        if (!string.IsNullOrEmpty(holdername) && !holdername.Equals(dto.Holdername))
            continue;
        if (!string.IsNullOrEmpty(type) && !type.Equals(dto.Type))
            continue;
        if (balance != default(double) && balance != dto.Balance)
            continue;
        if (!string.IsNullOrEmpty(status) && !status.Equals(dto.Status))
            continue;

        results.Add(dto);
    }

    return results;
}

Or making use of an expression tree

public List<AccountDto> getSearchedAccount(int accountid, int userid, string holdername, string type, double balance, string status)
{
    IQueryable<AccountDto> query = list.AsQueryable();

    if (accountid != default(int))
        query = query.Where(i => i.Accountid.Equals(accountid));
    if (userid != default(int))
        query = query.Where(i => i.Userid.Equals(userid));
    if (!string.IsNullOrEmpty(holdername))
        query = query.Where(i => i.Holdername.Equals(holdername));
    if (!string.IsNullOrEmpty(holdername))
        query = query.Where(i => i.Type.Equals(type));
    if (balance != default(double))
        query = query.Where(i => i.Balance.Equals(balance));
    if (!string.IsNullOrEmpty(holdername))
        query = query.Where(i => i.Status.Equals(status));

    return query.Select(i => i).ToList<AccountDto>();
}

Couple of thoughts

  • I'm sure your meant to use decimals for monetary values not doubles.
  • Create an object to represent your criteria so that you're not having to change the method signature every time you decide to add a new field

    public List getSearchedAccount(AccountSearchCritera criteria) { ... }

Upvotes: 1

Prasad Kanaparthi
Prasad Kanaparthi

Reputation: 6563

You can build aggregate filter in search criteria. I think below post has same what you are looking for. Try This

Upvotes: 0

Limey
Limey

Reputation: 2772

I think this might be what you are looking for: C# Coalesce

Upvotes: 0

bash.d
bash.d

Reputation: 13207

Why don't you create a method for that? In that method you can check if the property is null or empty or anything else.

private bool CheckAccount(AccountDto dto, int accountid, int userid, String holdername, string type, double balance, String status){
 bool isTrue = true;
 ...
 if(holdername != null){
    if(!dto.Holdername.Equals(holdername))
          return false;
 }
 ...
 return true; //all properties are true
}

Upvotes: 3

Matten
Matten

Reputation: 17631

It would go like this:

 if (accountid < 0 || dto.Accountid == accountid) 
     && ... 
     && (string.IsNullOrEmpty(holdername) || dto.Holdername.Equals(holdername)) 
     && ... )
    {
        results.Add(dto);
    }

Introduce an or for each condition which is true if the value is not set or the comparision matters. For example, if holdername is null or empty then the Equals of Holdername will not be evaluated.

Upvotes: 4

Related Questions