views:

276

answers:

2

Can I somehow get the object that caused a GenericADOException (constraint exception)?

Or How can I only flush one object so I can tell which one is the problem.

I have a list of object that are displayed in a form, and can be edited and added to. On flush it gives me a database exception but I can't tell which object gave the exception.

I can't move the constraint to nhibernate.

A: 

Have you tried using NHibernate Profiler? It should give you additional details as to which one is the problem.

ShaneC
I know by eyeball which one is causing the problem, the problem is how to determine that by code. I need to know in code which object is giving the problem so I can either modify or delete it.Think of a unique constraint in the database.
AngelBlaZe
While my understanding is that NHibernate is quite extensible and it's likely that you could get this information from NH I doubt it will be easy. At that point you have two options.1. Hope a specialist like Ayende Rahien shows up (doubtful -- more likely is hire him) to tell you how2. Since you should be treating this as a single unit of work (hence it's in a transaction) calling flush manually for each update seems like a more likely option to me.
ShaneC
Do you know how to flush one object manually? as in tell a session to only flush this object. I have list of them and being changed by databinding on a windows form, so I have no control of when they change as one can in web.
AngelBlaZe
A: 

By some googling I got to a post that was helpful, then by reading the nhibernate source I got to the following:

http://fabiomaulo.blogspot.com/2009/06/improving-ado-exception-management-in.html


'http://fabiomaulo.blogspot.com/2009/06/improving-ado-exception-management-in.html
'properties.Add("sql_exception_converter", "SmartCore.SmartDatabaseExceptionConverter, SmartCore")
Class SmartDatabaseExceptionConverter
    Implements ISQLExceptionConverter


    Public Function Convert(ByVal sqlException As System.Exception, ByVal message As String, ByVal sql As NHibernate.SqlCommand.SqlString) As NHibernate.ADOException Implements NHibernate.Exceptions.ISQLExceptionConverter.Convert

        Dim sqle As DbException
        sqle = ADOExceptionHelper.ExtractDbException(sqlException)
        '"could not update: [SmartCore.GL.Glaccount#1225]"
        Dim obname As String
        Dim key As String
        obname = ExtractUsingTemplate("could not update: [", "#", message)
        key = ExtractUsingTemplate("#", "]", message)

        Dim prikey As Integer
        prikey = Integer.Parse(key)

        sqle.Data.Add("obname", obname)
        sqle.Data.Add("prikey", key)

        If sqle.ErrorCode = 335544558 Then
            '"Operation violates CHECK constraint C_GLACCOUNT on view or table GLACCOUNT At trigger 'CHECK_56'"
            Dim checkname As String
            checkname = ExtractUsingTemplate("Operation violates CHECK constraint ", "on view or table ", sqle.Message)
            Return New SmartDatabaseConstraintException(message, sqle, obname, prikey, checkname)
            'Return New ConstraintViolationException(message, sqle, sql, checkname)
        End If

        Return SQLStateConverter.HandledNonSpecificException(sqlException, message, sql)
    End Function



    Protected Function ExtractUsingTemplate(ByVal templateStart As String, ByVal templateEnd As String, ByVal message As String) As String
        Dim templateStartPosition As Integer = message.IndexOf(templateStart)
        If templateStartPosition < 0 Then
            Return Nothing
        End If

        Dim start As Integer = templateStartPosition + templateStart.Length
        Dim [end] As Integer = message.IndexOf(templateEnd, start)
        If [end] < 0 Then
            [end] = message.Length
        End If

        Return message.Substring(start, [end] - start).Trim()

    End Function
End Class


'USAGE
        Try
            _scope.Flush()
        Catch ex As SmartDatabaseConstraintException
            If ex.ConstraintName = "C_GLACCOUNT" Then
                Dim gla As GL.Glaccount
                gla = GL.Glaccount.Find(ex.EntityId) 'should be fast from entity cache
                msgboxError(gla.description & " is duplicate please rename")
            Else
                msgboxError(ex.Message)
            End If
        End Try


I had to adapt it to work with my slightly outdated nhibernate version (2.1 from march) I will have to adapt the above slightly to work with newer versions where there is a AdoExceptionContextInfo from which one can get the object name and ID. Nhibernate is good!

AngelBlaZe