0

I am trying to run an Async Method that has a loop to load some data from mySQL database.

The Await function does not stop the other tasks from running concurrently but they all depend on each other.

The results right now is duplicate DataGrid entries but the DataGrid does load Asynchronously. On fresh start of the program, everything works ok without any duplicates - not sure why this would happen!

How do I call an Async Function that returns data within an async loop?

        private async void LoadAsync_ProviderReport()
        {
            Progress.Visibility = Visibility.Visible;
            DataGrid.Opacity = 0.3;
            string FromDate = FromDatePicker.Date.Value.ToString("yyyy-MM-dd");
            string ToDate = ToDatePicker.Date.Value.ToString("yyyy-MM-dd");
            ProviderReport.Clear();
            await Get_ProviderReport(FromDate, ToDate, DataGrid) ;
            Progress.Visibility = Visibility.Collapsed;
            DataGrid.Opacity = 1;
        }

private async Task<ObservableCollection<ProviderReport>> Get_ProviderReport(string FromDate, string ToDate, DataGrid DG)
        {
            ProviderReport.Clear();

            ProviderReport ptotal = new ProviderReport();
            AcrylicBrush brush2 = new AcrylicBrush();
            brush2.TintColor = Windows.UI.Color.FromArgb(0, 150, 150, 150);
            brush2.TintLuminosityOpacity = 0.6;
            brush2.BackgroundSource = 0;
            brush2.TintOpacity = 0.8;
            ptotal.ProvBrush = brush2;
            ptotal.Provider = "Practice Total";
            decimal PracticeProduction = 0;
            decimal PracticeAdjustments = 0;
            decimal PracticeWriteoffs = 0;
            decimal PracticeIncome = 0;
            decimal PracticeNetProduction = 0;
            decimal PracticeWorkedDays = 0;
            decimal PracticeWorkedHours = 0;
            decimal PracticeApptsNumbers = 0;
            decimal PracticeApptsHours = 0;
            decimal PracticeApptsBroken = 0;
            decimal PracticePtsSeen = 0;
            decimal PracticePtsReappointed = 0;

            foreach (DataRow ProviderRow in Providers.Rows)
            {               
                // Practice Total Row
                int ProvNum = Int32.Parse(ProviderRow["ProvNum"].ToString());
                Style ProvStyle = ProviderRow["ProvStyle"] as Style;
                Brush ProvBrush = ProviderRow["ProvBrush"] as Brush;
                string Provider = ProviderRow["Abbr"].ToString() + " - " + ProviderRow["FName"].ToString() + " " + ProviderRow["LName"].ToString();

                decimal Production = await SQL.Functions.GetValue(SQL.Queries.Production, FromDate, ToDate, ProvNum);
                decimal Adjustments = await SQL.Functions.GetValue(SQL.Queries.Adjustments, FromDate, ToDate, ProvNum);
                decimal Writeoffs = await SQL.Functions.GetValue(SQL.Queries.Writeoffs, FromDate, ToDate, ProvNum);
                decimal Income = await SQL.Functions.GetValue(SQL.Queries.Income, FromDate, ToDate, ProvNum);
                decimal NetProduction = Production - Adjustments + Writeoffs;
                decimal WorkedDays = await SQL.Functions.GetValue(SQL.Queries.WorkedDays, FromDate, ToDate, ProvNum);
                decimal WorkedHours = await SQL.Functions.GetValue(SQL.Queries.WorkedHours, FromDate, ToDate, ProvNum);
                decimal ApptsNumbers = await SQL.Functions.GetValue(SQL.Queries.ApptsNumbers, FromDate, ToDate, ProvNum);
                decimal ApptsHours = await SQL.Functions.GetValue(SQL.Queries.ApptsHours, FromDate, ToDate, ProvNum);
                decimal ApptsBroken = await SQL.Functions.GetValue(SQL.Queries.ApptsBroken, FromDate, ToDate, ProvNum);
                decimal PtsSeen = await SQL.Functions.GetValue(SQL.Queries.PtsSeen, FromDate, ToDate, ProvNum);
                decimal PtsReappointed = await SQL.Functions.GetValue(SQL.Queries.PtsReappointed, FromDate, ToDate, ProvNum);

                PrintButton.Content = "Loading :" + Provider;

                PracticeProduction += Production;
                PracticeAdjustments += Adjustments;
                PracticeWriteoffs += Writeoffs;
                PracticeIncome += Income;
                PracticeNetProduction += NetProduction;
                PracticeWorkedDays += WorkedDays;
                PracticeWorkedHours += WorkedHours;
                PracticeApptsNumbers += ApptsNumbers;
                PracticeApptsHours += ApptsHours;
                PracticeApptsBroken += ApptsBroken;
                PracticePtsSeen += PtsSeen;
                PracticePtsReappointed += PtsReappointed;

                //Each Selected Provider Row
                bool ProvSelected = Convert.ToBoolean(ProviderRow["Selected"]);
                if (ProvSelected == true)
                {
                    ProviderReport pr = new ProviderReport();
                    pr.ProvNum = ProvNum;
                    pr.ProvStyle = ProvStyle;
                    pr.ProvBrush = ProvBrush;
                    pr.Provider = Provider;
                    pr.Production = Production;
                    pr.Adjustments = Adjustments;
                    pr.Writeoffs = Writeoffs;
                    pr.Income = Income;
                    pr.NetProduction = NetProduction;
                    pr.WorkedDays = WorkedDays;
                    pr.WorkedHours = WorkedHours;
                    pr.ApptsNumbers = ApptsNumbers;
                    pr.ApptsHours = ApptsHours;
                    pr.ApptsBroken = ApptsBroken;
                    pr.PtsSeen = PtsSeen;
                    pr.PtsReappointed = PtsReappointed;
                    ProviderReport.Add(pr);
                }
            }

            //SubTotal Row
            decimal TotalProduction = 0;
            decimal TotalAdjustments = 0;
            decimal TotalWriteoffs = 0;
            decimal TotalIncome = 0;
            decimal TotalNetProduction = 0;
            decimal TotalWorkedDays = 0;
            decimal TotalWorkedHours = 0;
            decimal TotalApptsNumbers = 0;
            decimal TotalApptsHours = 0;
            decimal TotalApptsBroken = 0;
            decimal TotalPtsSeen = 0;
            decimal TotalPtsReappointed = 0;
            foreach (ProviderReport p in ProviderReport)
            {
                TotalProduction += p.Production;
                TotalAdjustments += p.Adjustments;
                TotalWriteoffs += p.Writeoffs;
                TotalIncome += p.Income;
                TotalNetProduction += p.NetProduction;
                TotalWorkedDays += p.WorkedDays;
                TotalWorkedHours += p.WorkedHours;
                TotalApptsNumbers += p.ApptsNumbers;
                TotalApptsHours += p.ApptsHours;
                TotalApptsBroken += p.ApptsBroken;
                TotalPtsSeen += p.PtsSeen;
                TotalPtsReappointed += p.PtsReappointed;
            }
            ProviderReport psubtotal = new ProviderReport();
            psubtotal.Provider = "Selected Providers Total";

            AcrylicBrush brush = new AcrylicBrush();
            brush.TintColor = Windows.UI.Color.FromArgb(0, 200, 200, 200);
            brush.TintLuminosityOpacity = 0.6;
            brush.BackgroundSource = 0;
            brush.TintOpacity = 0.8;
            psubtotal.ProvBrush = brush;

            psubtotal.Production = SubTotals.Production = TotalProduction;
            psubtotal.Adjustments = SubTotals.Adjustments = TotalAdjustments;
            psubtotal.Writeoffs = SubTotals.Writeoffs = TotalWriteoffs;
            psubtotal.Income = SubTotals.Income = TotalIncome;
            psubtotal.NetProduction = SubTotals.NetProduction = TotalNetProduction;
            psubtotal.WorkedDays = SubTotals.WorkedDays = TotalWorkedDays;
            psubtotal.WorkedHours = SubTotals.WorkedHours = TotalWorkedHours;
            psubtotal.ApptsNumbers = SubTotals.ApptsNumbers = TotalApptsNumbers;
            psubtotal.ApptsHours = SubTotals.ApptsHours = TotalApptsHours;
            psubtotal.ApptsBroken = SubTotals.ApptsBroken = TotalApptsBroken;
            psubtotal.PtsSeen = SubTotals.PtsSeen = TotalPtsSeen;
            psubtotal.PtsReappointed = SubTotals.PtsReappointed = TotalPtsReappointed;
            ProviderReport.Add(psubtotal);

            // Practice Total Row
            ptotal.Production = PracticeTotals.Production = PracticeProduction;
            ptotal.Adjustments = PracticeTotals.Adjustments = PracticeAdjustments;
            ptotal.Writeoffs = PracticeTotals.Writeoffs = PracticeWriteoffs;
            ptotal.Income = PracticeTotals.Income = PracticeIncome;
            ptotal.NetProduction = PracticeTotals.NetProduction = PracticeNetProduction;
            ptotal.WorkedDays = PracticeTotals.WorkedDays = PracticeWorkedDays;
            ptotal.WorkedHours = PracticeTotals.WorkedHours = PracticeWorkedHours;
            ptotal.ApptsNumbers = PracticeTotals.ApptsNumbers = PracticeApptsNumbers;
            ptotal.ApptsHours = PracticeTotals.ApptsHours = PracticeApptsHours;
            ptotal.ApptsBroken = PracticeTotals.ApptsBroken = PracticeApptsBroken;
            ptotal.PtsSeen = PracticeTotals.PtsSeen = PracticePtsSeen;
            ptotal.PtsReappointed = PracticeTotals.PtsReappointed = PracticePtsReappointed;
            ProviderReport.Add(ptotal);

            //Return Data
            DG.DataContext = ProviderReport;
            return ProviderReport;
        }

public async Task<decimal> GetValue(string query, string FromDate, string ToDate, int ProvNum)
        {                
            var ParametersName = new List<string>() { "@FromDate", "@ToDate", "@ProvNum" };
            var ParametersValue = new List<string>() { FromDate, ToDate, ProvNum.ToString() };
            var DT = new DataTable();
            DT = await Task.Run(() => ExecuteMySQLQuery(query, ParametersName, ParametersValue)); ;
            decimal Output = default(decimal);
            try
            {
                if (DT.Rows.Count == 1)
                { Output = Convert.ToDecimal(DT.Rows[0][0]); }
                else
                { Output = Convert.ToDecimal(DT.Rows.Count); }

            }
            catch (Exception ex)
            {
                Output = Convert.ToDecimal("0");
            }
            return (Output);
        }

'''

First Run Results onNavigatedTo

Run From DateChangeEvent

5
  • 1
    Hi, can you provide a minimum runnable sample of the recurring problem so that we can reproduce your question? Or you can check the call stack of GetValue, there may be repeated calls somewhere. Commented Nov 12, 2019 at 6:16
  • Note that if you're using Connector/NET (MySql.Data), it doesn't support async programming at all: stackoverflow.com/a/50615230 It seems like you might have figured this out since you're explicitly using Task.Run. However, it would probably be better to switch to a truly async MySQL library: nuget.org/packages/MySqlConnector Commented Nov 12, 2019 at 14:44
  • @RichardZhang-MSFT 'GetValue' is being run only once and it runs a mySQL query basically asynchronously. 'Get_ProviderReport' is run once at page onNavigated to and whenever there is a change in the date as a 'CalendarDatePicker_DateChanged' event. Commented Nov 12, 2019 at 15:58
  • @BradleyGrainger the problem isn't with the MySQLConnector. I think it is that with a Task running a 'foreach' loop doesn't respect the 'await' and continues to process consecutive codes and comes back to the async 'GetValue' when the results are ready. This results in duplicate rows! Commented Nov 12, 2019 at 16:00
  • @RichardZhang-MSFT you were right! It was another method that was calling the 'Get_ProviderReport' method multiple times! Duuh! Commented Nov 12, 2019 at 16:38

1 Answer 1

0

It was another method that was calling the Get_ProviderReport method multiple times!

It seems that you have found the cause of the problem, then the most fundamental solution is to adjust the structure of the code, control the order in which the events are triggered.

After all, calling a method multiple times means multiple queries, which has a big impact on the performance of the software.

But there is also an immediate way. I don't know what your ProviderReport is, but it looks like a collection. We can use LinQ to perform a de-duplication before the data is filled into the DataGrid.

Before that, make sure you have rewritten the Equal method of ProviderReport.

ProviderReport.Distinct();

DG.DataContext = ProviderReport;

Best regards.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.