Reputation: 149
I have a method that calculates total amount for each month from the db, as shown.
public static List<Sale> ChartMonthlySalePerYear()
{
using (SQLiteConnection con = new SQLiteConnection(Connection.DatabaseLocationString))
{
SQLiteCommand cmd = null;
string query = String.Format("SELECT strftime('%m', SaleDate) AS month, SUM(AmountPaid) AS sum_amountpaid FROM {0} WHERE strftime('%Y', SaleDate) = @1 GROUP BY strftime('%m', SaleDate) ", Sale.TABLE_NAME);
cmd = new SQLiteCommand(query, con);
cmd.Parameters.Add(new SQLiteParameter("@1", Properties.Settings.Default.ChartYearlyDisplay));
con.Open();
SQLiteDataReader reader = cmd.ExecuteReader();
var list = new List<Sale>();
while (reader.Read())
{
Sale value = new Sale()
{
Months = reader["month"].ToString(),
SUMAmountPaid = Convert.ToDecimal(reader["sum_amountpaid"])
};
list.Add(value);
}
con.Close();
return list;
}
}
And it returns a List like these by months,
And this is where is use the method.
List<Sale> sum = SaleViewModel.ChartMonthlySalePerYear();
Jan = sum[0].SUMAmountPaid;
Feb = sum[1].SUMAmountPaid;
Mar = sum[2].SUMAmountPaid;
Apr = sum[3].SUMAmountPaid;
May = sum[4].SUMAmountPaid;
Jun = sum[5].SUMAmountPaid;
Jul = sum[6].SUMAmountPaid;
//For Ausgust
if (sum[7] != null)
Aug = 0;
else
Aug = sum[7].SUMAmountPaid;
//For September
if (sum[7] != null)
Sep = 0;
else
Sep = sum[7].SUMAmountPaid;
My challenge now is, there is no value for Aug & Sep, i want to check first before i give it a default value, but its throwing an Exception. Index was out of range. Must be non-negative and less than the size of the collection.
For Aug & Sep.
Thanks in advance.
Upvotes: 0
Views: 1748
Reputation: 1504
You should not be using an index approach to this, since your Sale
type has a Months
property that is being populated with the reader["month"]
value. You can determine whether a month exists by using a predicate (Func<Sale, bool>
delegate).
Using Linq, you can use the predicate with First
or FirstOrDefault
to return the first instance that evaluates to true
.
List<Sale> sum = SaleViewModel.ChartMonthlySalePerYear();
Jan = sum.Where((item) => item.Months == 1).Select((item) => item.SUMAmountPaid).DefaultIfEmpty(0).First();
Feb = sum.Where((item) => item.Months == 2).Select((item) => item.SUMAmountPaid).DefaultIfEmpty(0).First();
Mar = sum.Where((item) => item.Months == 3).Select((item) => item.SUMAmountPaid).DefaultIfEmpty(0).First();
Mar = sum.Where((item) => item.Months == 4).Select((item) => item.SUMAmountPaid).DefaultIfEmpty(0).First();
or,
Jan = sum.Any((item) => item.Months == 1) ? sum.First((item) => item.Months == 1).SUMAmountPaid : 0;
Feb = sum.Any((item) => item.Months == 2) ? sum.First((item) => item.Months == 2).SUMAmountPaid : 0;
Mar = sum.Any((item) => item.Months == 3) ? sum.First((item) => item.Months == 3).SUMAmountPaid : 0;
Apr = sum.Any((item) => item.Months == 4) ? sum.First((item) => item.Months == 4).SUMAmountPaid : 0;
you could just .ForEach
to iterate through your records and a switch case to map them.
List<Sale> sum = SaleViewModel.ChartMonthlySalePerYear()
.ForEach((item) => {
switch(item.Months)
{
case 1:
Jan = item.SUMAmountPaid;
break;
case 2:
Feb = item.SUMAmountPaid;
break;
case 3:
Mar = item.SUMAmountPaid;
break;
case 4:
Apr = item.SUMAmountPaid;
break;
case 5:
May = item.SUMAmountPaid;
break;
case 6:
Jun = item.SUMAmountPaid;
break;
case 7:
Jul = item.SUMAmountPaid;
break;
case 8:
Aug = item.SUMAmountPaid;
break;
case 9:
Sept = item.SUMAmountPaid;
break;
case 10:
Oct = item.SUMAmountPaid;
break;
case 11:
Nov = item.SUMAmountPaid;
break;
case 12:
Dec = item.SUMAmountPaid;
break;
default: //do nothing
break;
}
});
Ensuring that Jan
through Dec
are 0
by default.
Upvotes: 0
Reputation: 6060
You want to check if the index is less than or equal to the list's length before accessing that index to avoid index out of range exceptions:
if (sum.Count <= 7)
Aug = 0;
else
Aug = sum[7].SUMAmountPaid;
But this won't work like you are expecting if you have holes in your data. The index of the List isn't going to match the month if you do have holes in the data. If that is the case, consider using a Dictionary<int, Sale>()
:
var salesByMonth = new Dictionary<int, Sale>();
while (reader.Read())
{
Sale value = new Sale()
{
Months = reader["month"].ToString(),
SUMAmountPaid = Convert.ToDecimal(reader["sum_amountpaid"])
};
salesByMonth.Add(int.Parse(value.Months), value);
}
And
Sale value;
if (salesByMonth.TryGetValue(1, out value))
Jan = value.SUMAmountPaid;
else
Jan = 0;
if (salesByMonth.TryGetValue(2, out value))
Feb = value.SUMAmountPaid;
else
Feb = 0;
Upvotes: 6