title: Flutter provider interaction with database
body: <p>I am creating an app in flutter to manage personal expense. I am using the provider package but am facing problems implementing it. I have created the following provider:</p>
  <pre><code>class ExpensesProvider with ChangeNotifier {
    List&lt;Expense&gt; _recentExpensesList;
    List&lt;CategorywiseAmount&gt; _mostExpensiveCategoriesAmountsList;
    double _todayExpenses;
    double _lastSevenDaysExpenses;
    double _thisMonthExpenses;
    List&lt;MonthAndYear&gt; _distinctMonthsAndYearsList;
    List&lt;int&gt; _distinctYearsList;
  
    ExpensesProvider() {
      _loadDataFromDatabase();
    }
  
    List&lt;Expense&gt; get recentExpensesList {
      return _recentExpensesList;
    }
  
    double get todayExpenses {
      return _todayExpenses;
    }
  
    double get lastSevenDaysExpenses {
      return _lastSevenDaysExpenses;
    }
  
    double get thisMonthExpenses {
      return _thisMonthExpenses;
    }
  
    List&lt;CategorywiseAmount&gt; get mostExpensiveCategoriesAmountsList {
      return _mostExpensiveCategoriesAmountsList;
    }
  
    List&lt;MonthAndYear&gt; get distinctMonthsAndYearsList {
      return _distinctMonthsAndYearsList;
    }
  
    List&lt;int&gt; get distinctYearsList {
      return _distinctYearsList;
    }
  
    void _loadDataFromDatabase() async {
      DateTime currentDateTime = DateTime.now();
      _recentExpensesList = await ExpenseRepository.getRecentExpenses();
      _todayExpenses = await ExpenseRepository.getDayTotalExpenses(currentDateTime.day, currentDateTime.month, currentDateTime.year);
      _lastSevenDaysExpenses = await ExpenseRepository.getLastSevenDaysExpenses();
      _thisMonthExpenses = await ExpenseRepository.getMonthTotalExpenses(currentDateTime.month, currentDateTime.year);
      _mostExpensiveCategoriesAmountsList = await ExpenseRepository.getMostExpensiveCategoriesListForMonth(month: currentDateTime.month, year: currentDateTime.year);
      _distinctMonthsAndYearsList = await ExpenseRepository.getMonthAndYearListHavingExpenses();
      _distinctYearsList = await ExpenseRepository.getDistinctYearListHavingExpenses();
      notifyListeners();
    }
  
    Future&lt;int&gt; addExpense(Expense expense) async {
      final int id = await ExpenseRepository.addExpense(expense);
      _loadDataFromDatabase();
      notifyListeners();
      return id;
    }
  
    Future&lt;int&gt; deleteExpense(int expenseId) async {
      final int id = await ExpenseRepository.deleteExpense(expenseId);
      _loadDataFromDatabase();
      notifyListeners();
      return id;
    }
  
    Future&lt;int&gt; updateExpense(Expense expense) async {
      final int id = await ExpenseRepository.updateExpense(expense);
      _loadDataFromDatabase();
      notifyListeners();
      return id;
    }
  
    Future&lt;int&gt; updateCategoryNameOfExpenses({
      @required String oldCategoryName,
      @required String newCategoryName,
    }) async {
      int renamedCategoryCount = await ExpenseRepository.updateCategoryNameOfExpenses(oldCategoryName: oldCategoryName, newCategoryName: newCategoryName);
      _loadDataFromDatabase();
      notifyListeners();
      return renamedCategoryCount;
    }
  
   /***********************************
    * I wish to have/use these below functions with this provider
    * but don't know how to get these working.
    * I mean i don't know how will i pass argument to these methods, and even then
    * i will need to create private variables for each of these which are going to 
    * take unnecessary memory but i don't know what else to do, any alternates?
    ***********************************/
    Future&lt;List&lt;Expense&gt;&gt; getExpensesForMonth({@required int month, @required int year}) async {
      return await ExpenseRepository.getExpensesForMonth(month: month, year: year);
    }
  
    Future&lt;List&lt;Expense&gt;&gt; getExpensesForMonthForPaymentType({@required int month, @required int year, @required int paymentTypeId}) async {
      return await ExpenseRepository.getExpensesForMonthForPaymentType(month: month, year: year, paymentTypeId: paymentTypeId);
    }
  
    Future&lt;List&lt;Expense&gt;&gt; getLastNTransactions({@required int numberOfTransactions}) async {
      return await ExpenseRepository.getLastNTransactions(numberOfTransactions);
    }
  }
  </code></pre>
  <p>The Expense model is</p>
  <pre><code>class Expense {
    int id;
    String name;
    double amount;
    int paymentTypeId;
    String category;
    int day;
    int month;
    int year;
    int hour;
    int minute;
    int second;
  
    Expense(
        {@required this.name,
        @required this.day,
          @required this.month,
          @required this.year,
          @required this.hour,
          @required this.minute,
          @required this.second,
        @required this.amount,
        @required this.paymentTypeId,
        @required this.category});
  }
  </code></pre>
  <p>and here is the ExpenseRepository</p>
  <pre><code>class ExpenseRepository {
    static Future&lt;int&gt; addExpense(Expense expense) async {
      return await ExpensesDatabaseService().insertExpense(expense);
    }
  
    static Future&lt;int&gt; deleteExpense(int expenseId) async {
      return await ExpensesDatabaseService().deleteExpense(expenseId);
    }
  
    static Future&lt;int&gt; updateCategoryNameOfExpenses({
      @required String oldCategoryName,
      @required String newCategoryName,
    }) async {
      return await ExpensesDatabaseService().updateCategoryNameOfExpenses(
          oldCategoryName: oldCategoryName, newCategoryName: newCategoryName);
    }
  
    static Future&lt;List&lt;Expense&gt;&gt; getAllExpenses({@required int month}) async {
      return await mockService.getAllExpensesData(month: month);
    }
  
    //This method return most recent expenses
    static Future&lt;List&lt;Expense&gt;&gt; getRecentExpenses() async {
      print('*** Recent expenses service called ');
      return await ExpensesDatabaseService().getRecentExpenses();
    }
  
    static Future&lt;List&lt;CategorywiseAmount&gt;&gt; getAllCategorywiseAmountsListForMonth(
        {@required int month, @required int year}) async {
      return await ExpensesDatabaseService()
          .getAllCategorywiseAmountsListForMonth(month, year);
    }
  
    static Future&lt;List&lt;PaymentMethodWiseAmount&gt;&gt;
        getPaymentMethodwiseAmountsListForMonth(
            {@required int month, @required int year}) async {
      return await ExpensesDatabaseService()
          .getPaymentMethodwiseAmountsListForMonth(month, year);
    }
  
    static Future&lt;List&lt;PaymentMethodWiseAmount&gt;&gt;
        getPaymentMethodwiseAmountsListForYear({@required year}) async {
      return await ExpensesDatabaseService()
          .getPaymentMethodwiseAmountsListForYear(year);
    }
  
    static Future&lt;List&lt;CategorywiseAmount&gt;&gt; getAllCategorywiseAmountsListForYear(
        {@required year}) async {
      return await ExpensesDatabaseService()
          .getAllCategorywiseAmountsListForYear(year);
    }
  
    static Future&lt;List&lt;CategorywiseAmount&gt;&gt;
        getMostExpensiveCategoriesListForMonth(
            {@required int month, @required int year}) async {
      return await ExpensesDatabaseService()
          .getMostExpensiveCategoriesListForMonth(month, year);
    }
  
    static Future&lt;List&lt;Expense&gt;&gt; getExpensesForMonth(
        {@required int month, @required int year}) async {
      return await ExpensesDatabaseService().getExpensesForMonth(month, year);
    }
  
    static Future&lt;List&lt;Expense&gt;&gt; getExpensesForMonthForPaymentType(
        {@required int month,
        @required int year,
        @required int paymentTypeId}) async {
      return await ExpensesDatabaseService()
          .getExpensesForMonthForPaymentType(month, year, paymentTypeId);
    }
  
    static Future&lt;List&lt;Expense&gt;&gt; getExpensesForYearForPaymentType(
        {@required int year, @required paymentTypeId}) async {
      return await ExpensesDatabaseService()
          .getExpensesForYearForPaymentType(year, paymentTypeId);
    }
  
    static Future&lt;List&lt;Expense&gt;&gt; getLastNTransactions(
        int numberOfTransactions) async {
      return await ExpensesDatabaseService()
          .getLastNTransactions(numberOfTransactions);
    }
  
    static Future&lt;List&lt;Expense&gt;&gt; getExpensesForSearchString(
        String searchString) async {
      return await ExpensesDatabaseService()
          .getExpensesForSearchString(searchString);
    }
  
    static Future&lt;List&lt;Expense&gt;&gt; getExpensesForCategoryForMonth(
        int month, int year, String categoryName) async {
      return await ExpensesDatabaseService()
          .getExpensesForCategoryForMonth(month, year, categoryName);
    }
  
    static Future&lt;List&lt;Expense&gt;&gt; getExpensesForCategoryForYear(
        int year, String categoryName) async {
      return await ExpensesDatabaseService()
          .getExpensesForCategoryForYear(year, categoryName);
    }
  
    static Future&lt;List&lt;MonthYearAmount&gt;&gt; getMonthlyTotalsForYear(int year) async {
      return await ExpensesDatabaseService().getMonthlyTotalsForYear(year);
    }
  
    static Future&lt;List&lt;int&gt;&gt; getDistinctYearListHavingExpenses() async {
      return await ExpensesDatabaseService().getDistinctYearListHavingExpenses();
    }
  
    static Future&lt;double&gt; getDayTotalExpenses(
        int day, int month, int year) async {
      return await ExpensesDatabaseService()
          .getDayTotalExpenses(day, month, year);
    }
  
    static Future&lt;double&gt; getLastSevenDaysExpenses() async {
      return await ExpensesDatabaseService().getLastSevenDaysTotalExpenses();
    }
  
    static Future&lt;double&gt; getMonthTotalExpenses(int month, int year) async {
      return await ExpensesDatabaseService().getMonthTotalExpenses(month, year);
    }
  
    static Future&lt;List&lt;MonthAndYear&gt;&gt; getMonthAndYearListHavingExpenses() async {
      return await ExpensesDatabaseService().getMonthAndYearListHavingExpenses();
    }
  
    static Future&lt;List&lt;ExpenseCategory&gt;&gt; getAllCategories() async {
      return await CategoriesDatabaseService().getAllCategories();
    }
  
    static Future&lt;int&gt; addCategory(ExpenseCategory category) async {
      return await CategoriesDatabaseService().insertCategory(category);
    }
  
    static Future&lt;ExpenseCategory&gt; getCategoryByName(String categoryName) async {
      return await CategoriesDatabaseService().getCategoryByName(categoryName);
    }
  
    static Future&lt;int&gt; deleteCategory(int categoryId) async {
      return await CategoriesDatabaseService().deleteCategory(categoryId);
    }
  
    static Future&lt;int&gt; updateCategory(ExpenseCategory category) async {
      return await CategoriesDatabaseService().updateCategory(category);
    }
  
    static Future&lt;int&gt; updateExpense(Expense expense) async {
      return await ExpensesDatabaseService().updateExpense(expense);
    }
  }
  </code></pre>
  <p>The CRUD operations work just fine. However, consider the following flow:
  <a href="https://i.stack.imgur.com/hSSGp.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/hSSGp.jpg" alt="enter image description here" /></a>
  Here i am generating a report that shows all expenses for a payment type chosen by the user. I am trying to make the expense list (screen 3) a generic list screen (to reduce code duplication) that would take any list of expenses (based on different reports like monthly, yearly reports etc.) and allow the users to edit or delete any expense. So, when a user taps on a payment type in screen 2 (e.g., credit card), a list of expenses is generated based on the selected month and payment type using</p>
  <pre><code>ExpenseRepository.getExpensesForMonthForPaymentType(
        month: month, 
        year: year,
        paymentTypeId: paymentMethodAmountsList[index].paymentTypeId,
        )
  </code></pre>
  <p>and then the expenses list screen is launched like so...</p>
  <pre><code>Navigator.pushNamed(
                    context, ExpenseListWithEditAndDeleteButtonsScreen.routeName,
                    arguments: ArgumentsForExpenseList
                                (expenseList: expenseList, 
                                 pageTitle: PaymentTypeHelper.getPaymentTypeName(paymentMethodAmountsList[index].paymentTypeId),),
         );
  </code></pre>
  <p>The problem arises when the user edits/deletes an expense using edit/delete button on screen 3 of above image. In context of the above image:</p>
  <ol>
  <li>If a user edits an expense then how can i update the list and how will the previous screen (screen 2 in image) get updated? I tried to create the necessary methods/functions in the expenses_provider file but i am now more confused about the providers as ever! I am unable to figure out how to get these working. It is easy to use providers where you need to reload all records but here i need to reload selective records based on the month and payment type which are chosen by the user on a previous screen. Even if i create another private variable and getter in the expenses provider (e.g. _expensesForMonthForPaymentType) and load data into it using <code>getExpensesForMonthForPaymentType</code> method of the given repository, how do i supply the required arguments to the <code>getExpensesForMonthForPaymentType</code> method? And since i am trying to make the screen 3 a generic re-usable expenses list screen with edit and delete options, it doesn't make sense to put a dedicated private variable for each report in the ExpensesProvider. So my question is how do i do what i want to achieve here? To summarize, what i intend is that screen 3 is a generic re-usable screen that just takes a list of expenses and has options to edit and delete each expense. The actual expense list passed to this widget (screen 3) can vary based on different reports and is usually generated one level before it. The only problem is that when a user edits/deletes an expense from screen 3/4, how will it get updated on screen 2 and 3? Right now i am not using any consumer for screens 2 and 3 as i am yet to figure out what needs to be done in the provider, which is what i am asking in the first place.</li>
  <li>If my implementation of provider is flawed, please have some courtesy to provide a detailed answer and a solution (if possible) as i couldn't find any detailed docs or any other such resource related to my use case. There is no resource which provides in-depth info about provider+database scenario.</li>
  </ol>