How to trap SQL2005 RI messages to show a nice message to the user?


Author
Message
Edhy Rijo
E
StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)
Group: StrataFrame Users
Posts: 2.4K, Visits: 23K
Hi,

When trying to delete a parent record, the MS-SQL2005 throws an execption preventing the deletion of the record, which is just fine.  Is there a way to trap this exception and display a more user friendly message? or is there something in SF tha will take care of this for us?

Here is the Exception message:

SqlException
  The DELETE statement conflicted with the REFERENCE constraint "Has_many". The conflict occurred in database "ATR", table "dbo.ServiceCalls", column 'FK_Customers'.
The statement has been terminated.

Source     : .Net SqlClient Data Provider

Stack Trace:
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at MicroFour.StrataFrame.Data.DbDataSourceItem.InternalExecuteNonQuery(DbCommand Command, Boolean IsTransactional, String TransactionKey)
   at MicroFour.StrataFrame.Data.DbDataSourceItem.ExecuteNonQuery(DbCommand Command, Boolean IsTransactional, String TransactionKey)
   at MicroFour.StrataFrame.Data.DataLayer.DeleteByPrimaryKey(PrimaryKeyValue PKValue, DataRow Row)
   at MicroFour.StrataFrame.Business.BusinessLayer.DeleteByPrimaryKey(PrimaryKeyValue PKValue)
   at MicroFour.StrataFrame.Business.BusinessLayer.DeleteCurrentRow(Boolean CheckSecurity, Boolean OnlyMarkAsDeleted)
   at ATR_System.frmCustomers.tsiDelete_Click(Object sender, EventArgs e) in E:\Visual Studio 2005\StrataFrame Projects\ATR Systems\ATR System with not security\ATR System\Forms\frmCustomers.vb:line 217
   at System.Windows.Forms.ToolStripItem.RaiseEvent(Object key, EventArgs e)
   at System.Windows.Forms.ToolStripItem.HandleClick(EventArgs e)
   at System.Windows.Forms.ToolStripItem.HandleMouseUp(MouseEventArgs e)
   at System.Windows.Forms.ToolStrip.OnMouseUp(MouseEventArgs mea)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ToolStrip.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativewindow.WndProc(Message& m)
   at System.Windows.Forms.Nativewindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)



Edhy Rijo

Paul Chase
Paul Chase
Advanced StrataFrame User (576 reputation)Advanced StrataFrame User (576 reputation)Advanced StrataFrame User (576 reputation)Advanced StrataFrame User (576 reputation)Advanced StrataFrame User (576 reputation)Advanced StrataFrame User (576 reputation)Advanced StrataFrame User (576 reputation)Advanced StrataFrame User (576 reputation)Advanced StrataFrame User (576 reputation)
Group: Forum Members
Posts: 414, Visits: 2.8K
Hi,

You can set the AutoShowSavingErrors property to false and then handle the error saving event to display or suppress errors however you see fit.

Edhy Rijo
E
StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)
Group: StrataFrame Users
Posts: 2.4K, Visits: 23K
Hi Paul,

Thanks, but the ErrorSaving event is not fired when trying to delete a parent record.

Any other idea?

Edhy Rijo

Greg McGuffey
Greg McGuffey
Strategic Support Team Member (3.3K reputation)
Group: Forum Members
Posts: 2K, Visits: 6.6K
One option is to sub-class business layer and override the OnBeforeDelete method, then have logic within it that would check for any problems (and possibly fix them). Then have your BOs inherit from this sub-classed BO. Just be sure to call the base method, so the delete actually happens, events get raised.



Another options is to handle the BeforeDelete method in the BO and again do the data checking/fixing.



The first is best if you have lots of BOs that need the fix, the second if only one does. BigGrin
Edhy Rijo
E
StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)
Group: StrataFrame Users
Posts: 2.4K, Visits: 23K
Hi Greg,

I am testing a different approach using the BeforeDelete event of the form and going through the BO ChildBusinessObject's collection and if any of them have some record, then cancel the delete action and display my custom message.

Here the code I am testing:

Private Sub frmCustomers_BeforeDelete(ByVal e As MicroFour.StrataFrame.Business.BeforeDeleteEventArgs) Handles MyBase.BeforeDelete

     Dim Counter As Integer

     For Counter = 0 To e.BusinessObject.ChildBusinessObjects.Count

     If e.BusinessObject.ChildBusinessObjects.Item(Counter).Count > 0 Then

          e.Cancel = True

          MessageBox.Show("To delete this Customer you must delete all Building Address records first.", "Record Delete Warning...", MessageBoxButtons.OK, MessageBoxIcon.Information)

          Exit For

     End If

     Next

End Sub

The only problem I see with this approach is that the Ask for Delete messagebox will always show when entering the BeforeDelete event.Wink

I also tried using the BeforeDelete event of the Business Object, but then I could not use the MessageBox.Show(), I guess this is now allow from a BO code.BigGrin

Edhy Rijo

Jc Martinez
Jc Martinez
StrataFrame Beginner (24 reputation)StrataFrame Beginner (24 reputation)StrataFrame Beginner (24 reputation)StrataFrame Beginner (24 reputation)StrataFrame Beginner (24 reputation)StrataFrame Beginner (24 reputation)StrataFrame Beginner (24 reputation)StrataFrame Beginner (24 reputation)StrataFrame Beginner (24 reputation)
Group: Forum Members
Posts: 20, Visits: 59
You could trigger a cascade delete on all related records on the SQL side and tell the user that all related records will be deleted and ask if OK to continue....Cool

That way the user does not have to stop what he is doing and start a deleting process for all related records and come back and delete the parent record…Doze

At least that’s what I do in my apps and some times I even tell them how many related records will be deleted. This gives the user a chance to make a decision to continue or cancel the delete. Wink

Greg McGuffey
Greg McGuffey
Strategic Support Team Member (3.3K reputation)
Group: Forum Members
Posts: 2K, Visits: 6.6K
Related to using BeforeDelete Event

The delete confirmation is handled by the SF form (BaseForm actually). This can be turned off at the form level (so no SF delete conformation is used). See http://forum.strataframe.net/FindPost11030.aspx for some more info.



I believe the events would be raised:



- OnBeforeDelete of BusinessLayer raises BeforeDelete event of the BO



- The BaseForm (which the SF StandardForm inherits from, which you form inherits from) handles this event, does the delete confirmation and raises form's BeforeDelete event.



- Any handlers you have added to the BeforeDelete event get fired (like the one you posted)...so confirmation has already happened at this point.



- Any handlers of the form's BeforeDelete event fires.



I think another option to have more control over this would be to handle it in a sub-class of BusinessLayer, then override the OnBeforeDelete method. The you have control over when the BusinessLayer raises the events in the first place. You could also add you own event that could fire when the child records aren't already deleted, then handle that event to provide the message.



MessageBox not working form within a BO

I know of no reason why you couldn't use MessageBox within a BO....it's just a class like any other (including Form classes). You might want to verify that the code is ever called by stepping through it.



Referential Integerity and Cascading Deletes

I also usually use referential integrity with cascading deletes. To setup this, you would setup the building address table to have a Foreign Key to the customers table with ON DELETE CASCADE set. This enforces that no building addresses can be added that don't have valid customers and that when a customer is deleted, any associated building addresses are deleted as well.



When the db is setup this way, then I usually turn off the auto confirmation of delete messages for the form and provide my own, so I can remind the user that any building addresses will be deleted as well (JC's idea of presenting how many would be deleted is a nice touch). This type of setup has a couple of advantages:



- it ensures that the db doesn't have any data in it...period

- it is simpler to implement (setup FK on table, override delete message)

- typically faster, as the db handles checking referential integrity and the cascading deletes very fast



Hope that helps! BigGrin

StrataFrame Team
S
StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)
Group: StrataFrame Developers
Posts: 3K, Visits: 2.5K
Edhy,

Back to Paul's suggestion: You'll need to change the ErrorSavingMode to ContinueOnError before the ErrorSaving event will get fired.

On Greg's suggestion, it will work great, but you'll want to set the AutoShowDeleteConfirmation to False and show your own delete confirmation if the user is allowed to delete the message (because there are no children).

StrataFrame Team
S
StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)StrataFrame Developer (4.2K reputation)
Group: StrataFrame Developers
Posts: 3K, Visits: 2.5K
The other option would of course, be to wrap the Save() call in a Try/Catch and test the SqlErrors collection on the InnerException of the thrown BusinessLayerException.  I believe the foreign key validation will have a specific error type you can test on.
Edhy Rijo
E
StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)StrataFrame VIP (4.6K reputation)
Group: StrataFrame Users
Posts: 2.4K, Visits: 23K
Hi Ben,

Thanks for clarifications on this one.  I decided to handle this in the BO's BeforeDelete as follow, if you have any suggestion on how to improve this code, it will be greatly appreciated. Tongue

''' <summary>

''' Validate the Service Call before trying to delete it.

''' </summary>

''' <param name="e"></param>

''' <remarks></remarks>

Private Sub ServiceCallsBO1_BeforeDelete(ByVal e As MicroFour.StrataFrame.Business.BeforeDeleteEventArgs) Handles ServiceCallsBO1.BeforeDelete

     Dim LoopCounter As Integer = 0

     For Counter As Integer = 1 To e.BusinessObject.ChildBusinessObjects.Count

          If e.BusinessObject.ChildBusinessObjects.Item(LoopCounter).Count > 0 Then

               e.Cancel = True

               Me.AutoShowDeleteConfirmation = False

               MessageBox.Show("To delete this Service Call you must delete all related records first.", "Record Delete Warning...", MessageBoxButtons.OK, MessageBoxIcon.Information)

               Exit For

          End If

          LoopCounter += 1

     Next

End Sub



Edhy Rijo

GO

Merge Selected

Merge into selected topic...



Merge into merge target...



Merge into a specific topic ID...




Similar Topics

Reading This Topic

Login

Explore
Messages
Mentions
Search