Good Afternoon,
I’m currently attempting to work with the Entity Framework DbContext/Code First inside a winforms application. My class, PrintQueueItem, is mapped to a view inside the database that only returns PrintQueueItem that have a PrintStatus equal to ‘Pending’. This is displayed to the end-user via a DataGridView so they can view what’s to be batch printed at the end of the day. Users are able to add instances of PrintQueueItem and this is displayed inside the DataGridView as well.
My issue arises when I attempt to cancel an item that’s set to print. I set the PrintStatus to Cancelled and then run the ExecuteSqlCommand to update the database. After this, I try reload the information but the item is still displayed inside the DataGridView. I’m unsure why this is as when I get the count (via Local) after the information has been loaded again it has been decremented by one. Any idea why this would be as I thought the BindingList provides a 2-way sync for data-binding and the UI would be updated with the change in data?
PrintQueueItem (Model)
public class PrintQueueItem
{
public PrintQueueItem()
{
this.PrintQueueID = Guid.NewGuid();
this.PrintStatus = "Pending";
this.DateAdded = DateTime.Now;
}
public Guid PrintQueueID { get; set; }
public Guid DocumentID { get; set; }
public string PrintStatus { get; set; }
public DateTime DateAdded { get; set; }
public virtual Documentation Document { get; set; }
}
Initial Binding
this.printQueueBinding.DataSource = db.PrintQueue.Local.ToBindingList();
this.printQueueGridView.AutoGenerateColumns = false;
this.printQueueGridView.DataSource = printQueueBinding;
Update PrintStatus on PrintQueueItem and Reload
PrintQueueItem item = printQueueBinding.Current as PrintQueueItem;
if (item == null)
{
throw new ArgumentNullException("Could not obtain instance of selected 'PrintQueueItem'");
}
item.PrintStatus = "Cancelled";
this.db.Database.ExecuteSqlCommand("exec usp_PrintQueue_Update {0}, {1}",item.PrintQueueID, item.PrintStatus);
this.db.PrintQueue.Load();
Some Additional Notes
Instead of a call to the ExecuteSqlCommand, I tried calling SaveChanges but encountered an exception stating:
"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded."
I’m assuming this is because the item is no longer found in the view when it’s updated. Please let me know if this is not the case.
The reason for using a filtered view rather than filtering in the application is because BindingList doesn’t implement IBindingListView and I’m unable to implement the BindingList.Filter method to filter the data displayed inside the DataGridView. Any suggestions on this are welcome as well.
Thank you for your help.
After a couple beers and some time to let the jumbled mess of logic I had in my brain clear out from earlier today; I began to think of what was actually happening and then it hit me that when I attempted to call SaveChanges a concurrency exception was happening.
I failed to pay attention to the type of exception that was raised and thus failed to properly handle it. I’ve since updated my code to the following so when a DbUpdateConcurrencyException occurs (expected, since the view no longer contains the record) the entities that experience the issue are refreshed from the database:
Please let me know if there are better ways to go about this as I’m always open to other ideas and always interested in doing things the proper way. Have a great night!