4.7.2. Loading the Invoice Data

The following method loads the invoice headers:

  1. public void LoadInvoicesData() {
  2. var dbContext = AppVariables.getDbContext();
  3. var invoices =
  4. from invoice in dbContext.INVOICES
  5. where (invoice.INVOICE_DATE >= AppVariables.StartDate) &&
  6. (invoice.INVOICE_DATE <= AppVariables.FinishDate)
  7. orderby invoice.INVOICE_DATE descending
  8. select new InvoiceView
  9. {
  10. Id = invoice.INVOICE_ID,
  11. Cusomer_Id = invoice.CUSTOMER_ID,
  12. Customer = invoice.CUSTOMER.NAME,
  13. Date = invoice.INVOICE_DATE,
  14. Amount = invoice.TOTAL_SALE,
  15. Payed = (invoice.PAYED == 1) ? "Yes" : "No"
  16. };
  17. masterBinding.DataSource = invoices.ToBindingList();
  18. }

To simplify type casting, we define an InvoiceView class, rather than use some anonymous type. The definition is as follows:

  1. public class InvoiceView {
  2. public int Id { get; set; }
  3. public int Cusomer_Id { get; set; }
  4. public string Customer { get; set; }
  5. public DateTime? Date { get; set; }
  6. public decimal? Amount { get; set; }
  7. public string Payed { get; set; }
  8. public void Load(int Id) {
  9. var dbContext = AppVariables.getDbContext();
  10. var invoices =
  11. from invoice in dbContext.INVOICES
  12. where invoice.INVOICE_ID == Id
  13. select new InvoiceView
  14. {
  15. Id = invoice.INVOICE_ID,
  16. Cusomer_Id = invoice.CUSTOMER_ID,
  17. Customer = invoice.CUSTOMER.NAME,
  18. Date = invoice.INVOICE_DATE,
  19. Amount = invoice.TOTAL_SALE,
  20. Payed = (invoice.PAYED == 1) ? "Yes" : "No"
  21. };
  22. InvoiceView invoiceView = invoices.ToList().First();
  23. this.Id = invoiceView.Id;
  24. this.Cusomer_Id = invoiceView.Cusomer_Id;
  25. this.Customer = invoiceView.Customer;
  26. this.Date = invoiceView.Date;
  27. this.Amount = invoiceView.Amount;
  28. this.Payed = invoiceView.Payed;
  29. }
  30. }

The Load method allows us to update one added or updated record in the grid quickly, instead of completely reloading all records. Here is the code of the event handler for clicking the Add button:

  1. private void btnAddInvoice_Click(object sender, EventArgs e) {
  2. var dbContext = AppVariables.getDbContext();
  3. var invoice = dbContext.INVOICES.Create();
  4. using (InvoiceEditorForm editor = new InvoiceEditorForm()) {
  5. editor.Text = "Add invoice";
  6. editor.Invoice = invoice;
  7. // Form Close Handler
  8. editor.FormClosing += delegate (object fSender, FormClosingEventArgs fe) {
  9. if (editor.DialogResult == DialogResult.OK) {
  10. try {
  11. // get next sequence value
  12. invoice.INVOICE_ID = dbContext.NextValueFor("GEN_INVOICE_ID");
  13. // add a record
  14. dbContext.INVOICES.Add(invoice);
  15. // trying to save the changes
  16. dbContext.SaveChanges();
  17. // add the projection to the grid list
  18. ((InvoiceView)masterBinding.AddNew()).Load(invoice.INVOICE_ID);
  19. }
  20. catch (Exception ex) {
  21. // display error
  22. MessageBox.Show(ex.Message, "Error");
  23. // Do not close the form to correct the error
  24. fe.Cancel = true;
  25. }
  26. }
  27. };
  28. // show the modal form
  29. editor.ShowDialog(this);
  30. }
  31. }

In our primary modules, the similarly-named method called dbContext.Refresh but, here, a record is updated by by calling the Load method of the InvoiceView class. The reason for the difference is that dbContext.Refresh is used to update entity objects, not the objects that can be produced by complex LINQ queries.

The code of the event handler for clicking the Edit button:

  1. private void btnEditInvoice_Click(object sender, EventArgs e) {
  2. var dbContext = AppVariables.getDbContext();
  3. // find entity by id
  4. var invoice = dbContext.INVOICES.Find(this.CurrentInvoice.Id);
  5. if (invoice.PAYED == 1) {
  6. MessageBox.Show("The change is not possible, the invoice has already been paid.",
  7. "Error");
  8. return;
  9. }
  10. using (InvoiceEditorForm editor = new InvoiceEditorForm()) {
  11. editor.Text = "Edit invoice";
  12. editor.Invoice = invoice;
  13. // Form Close Handler
  14. editor.FormClosing += delegate (object fSender, FormClosingEventArgs fe) {
  15. if (editor.DialogResult == DialogResult.OK) {
  16. try {
  17. // trying to save the changes
  18. dbContext.SaveChanges();
  19. // refresh
  20. CurrentInvoice.Load(invoice.INVOICE_ID);
  21. masterBinding.ResetCurrentItem();
  22. }
  23. catch (Exception ex) {
  24. // display error
  25. MessageBox.Show(ex.Message, "Error");
  26. // Do not close the form to correct the error
  27. fe.Cancel = true;
  28. }
  29. }
  30. };
  31. editor.ShowDialog(this);
  32. }
  33. }

Here we needed to find an entity by the identifier provided in the current record. The CurrentInvoice is used to retrieve the invoice selected in the grid. This is how we code it:

  1. public InvoiceView CurrentInvoice {
  2. get {
  3. return (InvoiceView)masterBinding.Current;
  4. }
  5. }

Using the same approach, you can implement deleting the invoice header yourself.

Paying an Invoice

Besides adding, editing and deleting, we want one more operation for invoices: payment. Here is code for a method implementing this operation:

  1. private void btnInvoicePay_Click(object sender, EventArgs e) {
  2. var dbContext = AppVariables.getDbContext();
  3. var invoice = dbContext.INVOICES.Find(this.CurrentInvoice.Id);
  4. try {
  5. if (invoice.PAYED == 1)
  6. throw new Exception("The change is not possible, the invoice has already been paid.");
  7. invoice.PAYED = 1;
  8. // trying to save the changes
  9. dbContext.SaveChanges();
  10. // refresh record
  11. CurrentInvoice.Load(invoice.INVOICE_ID);
  12. masterBinding.ResetCurrentItem();
  13. }
  14. catch (Exception ex) {
  15. // display error
  16. MessageBox.Show(ex.Message, "Error");
  17. }
  18. }