3
\$\begingroup\$

Let's say that i have a database which contain cheese. I love cheese. Depending on the request my server is getting (c# WebApi), i have to filter user data accordingly. Maybe the user wants to only get cheese up to a certain date, or from a certain date, or between to dates. Maybe he wants all french cheese, or american cheese. My model works, but i dont like switchs, and i feel like there is a better way.

The model is as follow :

namespace myAPI.Models
{
    public enum CheeseFilter
    {
        Country,
        DateFrom,
        DateStart,
        DateBetween,
    };

    public class FilterQuery
    {
        public CheeseFilter? filter { get; set; }
        public DateTime? DateStart{ get; set; }
        public DateTime? DateEnd{ get; set; }
        public String Country{ get; set; }

    }
}

This model is what's get filled [FromPost] Now, i'm creating a tuple which will hold the StoredProcedure name (Basically, a select with where, order by, etc), its parameters, and the choosen filter, like so :

       private Tuple<CheeseFilter, String, List<SqlParameter>> LoadedCheeseWithOptions;

And where i actually fill it :

public bool CheeseFilterTuple()
        {
            bool flag = false;
            List<SqlParameter> options = new List<SqlParameter>();
            String SPName = "ERROR";
            DateTime tmp = new DateTime(); // ForChecking GoodFormating of datetimes
            DateTime tmp2 = new DateTime();
            switch (GetMode().Value)
            {
                case CheeseFilter.DateFrom:
                    flag = !String.IsNullOrWhiteSpace(dateStart) && DateTime.TryParseExact(dateStart, TMP_DATEFORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out tmp);;
                    options.Add( new SqlParameter() { Name =  "@DateStart", Value = tmp.ToString("yyyyMMdd")});
                    SPName = "Cheese_FromDate";
                    break;
                case CheeseFilter.DateStart:
                    flag = !String.IsNullOrWhiteSpace(dateEnd) && DateTime.TryParseExact(dateEnd, TMP_DATEFORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out tmp);
                    options.Add(new SqlParameter() { Name = "@DateEnd", Value = tmp.ToString("yyyyMMdd") });
                    SPName = "Cheese_To_Date";
                    break;
                case CheeseFilter.BetweenDates:
                    flag = !String.IsNullOrWhiteSpace(dateStart) && DateTime.TryParse(dateStart, out tmp) && !String.IsNullOrWhiteSpace(dateEnd) && DateTime.TryParse(dateEnd, out tmp2);
                    options.Add( new SqlParameter() { Name = "@DateStart",Value =  tmp.ToString("yyyyMMdd")}); //Converting for sqlServer
                    options.Add( new SqlParameter() { Name = "@DateEnd", Value = tmp2.ToString("yyyyMMdd")});
                    SPName = "Cheese_Between_Date";
                    break;

            }
            LoadedCheeseWithOptions = new Tuple<CheeseFilter, string, List<SqlParameter>>(GetMode().Value, SPName, options);
            return flag;
        }

GetMode() is just transforming the CheeseFilter? into a CheeseFilter.

The main issue is that, with this last bit of code here, i feel like with every new filter that I might get asked to create will mean adding another block of code to the pile, which I think is a poor man's solution.

So I'm asking you for some guidelines, or even better ways that'd you handle better this optional filter loading.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ What is it you don't like, adding the enum value, adding the filter query member, or adding the code that actually sets up the query? Is there a reason that FilterStringA can't just be FilterString or a collection and shared for all string filters? I don't think without the building code, particularly with your obfuscation this is lacking context. \$\endgroup\$
    – forsvarir
    Jun 24, 2016 at 14:47
  • 1
    \$\begingroup\$ I can understand your need to obfuscate the code. However, if you do so, please do it in a realistic way. (Make up a parallel problem to solve, if you have to.) Otherwise, we can't tell what is real and what is fake, and we can't meaningfully review the code. \$\endgroup\$ Jun 24, 2016 at 18:00
  • \$\begingroup\$ @200_success Hi ! I've actually done my due dilligence while researching my issue. Turns out building a tuple solves all my troubles. I could edit the answer into a workable exemple if some folks are still interested tho \$\endgroup\$
    – Mekap
    Jun 27, 2016 at 13:01
  • 1
    \$\begingroup\$ @200_success I've actually reworked my question. I've decided to talk cheese instead of work. Tell me if it needs more information for an accurate answer \$\endgroup\$
    – Mekap
    Jun 30, 2016 at 15:13

1 Answer 1

2
\$\begingroup\$

Your code is really hard to follow. It reads and modifies a lot of local fields/properties that are somewhere hidden. I tried to refactor it but it's still buggy I believe as some parameters are unclear. Nevertheless it should give you an idea how to improve it.


Using Tuple is a quick and dirty way to test something because you almost instantly forget what the properties are for as they are simply named ItemX. If you plan to use this code longer then just for experiments I'd use a real class.

You should pass all the parameters that the function needs instead reading them from the some fields or properties... unless it's a part of some class which we don't know.

In particular you could create filter criteria for passing the parameters and return a cheese filter as a result.

You don't need to check the date string for null/empty, the TryParse won't throw on null, that's what it is for.

Work on your variable names. tmp, tmp2 are not good at all. Give them real names, like dateStart or dateEnd or even tmpDateStart but just tmp isn't good enough.

Here's an example that I managed to piece together:

public class FilterCriteria
{
    public CheeseFilter? filter { get; set; }
    public string DateStart { get; set; }
    public string DateEnd { get; set; }
    public String Country { get; set; }
}

class CheeseFilter
{
    public FilterCriteria Criteria { get; set; }
    public string SPName { get; set; }
    public List<SqlParameter> SqlParameters { get; set; }
}

public CheeseFilter CreateCheeseFilter(FilterCriteria filterCriteria)
{
    var isValidDateFormat = false;
    var sqlParameters = new List<SqlParameter>();
    var SPName = "ERROR";

    var dateStart = new DateTime(); // ForChecking GoodFormating of datetimes
    var dateEnd = new DateTime();

    switch (GetMode().Value)
    {
        case CheeseFilter.DateFrom:
            isValidDateFormat = DateTime.TryParseExact(filterCriteria.DateStart, TMP_DATEFORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out tmp);;
            if (!isValidDateFormat) retrun null;

            sqlParameters.Add(new SqlParameter() { Name =  "@DateStart", Value = tmp.ToString("yyyyMMdd")});
            SPName = "Cheese_FromDate";
            break;

        case CheeseFilter.DateStart:
            isValidDateFormat = DateTime.TryParseExact(filterCriteria.DateStart, TMP_DATEFORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out tmp);
            if (!isValidDateFormat) retrun null;

            sqlParameters.Add(new SqlParameter() { Name = "@DateEnd", Value = tmp.ToString("yyyyMMdd") });
            SPName = "Cheese_To_Date";
            break;

        case CheeseFilter.BetweenDates:
            isValidDateFormat = 
                DateTime.TryParse(filterCriteria.DateStart, out dateStart) && 
                DateTime.TryParse(filterCriteria.DateEnd, out dateEnd);
            if (!isValidDateFormat) retrun null;

            sqlParameters.Add( new SqlParameter() { Name = "@DateStart",Value =  tmp.ToString("yyyyMMdd")}); //Converting for sqlServer
            sqlParameters.Add( new SqlParameter() { Name = "@DateEnd", Value = tmp2.ToString("yyyyMMdd")});
            SPName = "Cheese_Between_Date";
            break;

    }

    return new CheeseFilter 
    { 
        Criteria = GetMode().Value
        SPName = SPName
        SqlParameters = options
    };
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.