Mark Gilbert's Blog

Science and technology, served light and fluffy.

When I said now, I meant NOW! Castle ActiveRecord Transactions

I’m using Castle ActiveRecord (AR) for the major project that I’m working on right now (I have several lieutenants, but just the one major), and this past week I hit a snag.  I have one part of the web application that I felt was too complex to try to implement purely with AR objects, so I built a traditional query that would pull everything I needed together and my business layer returns it as a collection of custom objects.  The snag surfaced when I tried to write an object to the database using AR, and then immediately read it back using this query.

What I was trying to do was allow the user to click on a button that would cause the record to be written.  Then, I would run my custom query to refresh an in-session structure showing the user’s current progress.  Finally, the new page was rendered, showing the user’s updated progress.  What I was seeing was that the record was not being committed back to the database until after the page was rendered.  The new data WAS still now accessible via the AR framework (using any number of methods of finding it), but Doug (one of my colleagues) and I reasoned that AR was simply caching the data, waiting for the best opportunity to persist it back to the database.

With Doug’s help and after several passes using the debugger, we finally narrowed down where the record was actually being written – the Application_EndRequest event handler in my Global.asax.  You see, my Application_BeginRequest handler would create an AR SessionScope object, and stuff it into session.  Then the Application_EndRequest handler would pull it back out of session and dispose of it. 

Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)

    If BlahAppSettings.Core.EnableActiveRecordLogging Then
        log4net.Config.XmlConfigurator.Configure()
    End If

    ' Initialize ActiveRecord
    Dim activeRecordConfig As IConfigurationSource = Config.ActiveRecordSectionHandler.Instance
    Dim objectAssemblies As System.Reflection.Assembly() = New Reflection.Assembly() {System.Reflection.Assembly.Load("BlahBusinessServices")}
    ActiveRecordStarter.Initialize(objectAssemblies, activeRecordConfig)

    AddHandler Me.EndRequest, AddressOf Application_EndRequest
End Sub


Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
    ' Enable ActiveRecord Session Scope for the request
    HttpContext.Current.Items.Add("ar.sessionscope", New SessionScope())
End Sub


Sub Application_EndRequest(ByVal sender As Object, ByVal e As EventArgs)
    ' Clean up the ActiveRecord Session Scope
    Try
        Dim scope As SessionScope = CType(HttpContext.Current.Items("ar.sessionscope"), SessionScope)
        If Not scope Is Nothing Then
            scope.Dispose()
            HttpContext.Current.Items.Remove("ar.sessionscope")
        End If
    Catch ex As Exception
        Throw
    End Try
End Sub

It was the .Dispose call in Application_EndRequest that was forcing the record back to the database.  I didn’t want to try to force the .Dispose in my page, but I did need that record written out sooner than EndRequest.

After doing some digging into AR sessions, I found this post on Stack Overflow: http://stackoverflow.com/questions/38729/do-you-know-how-to-implement-transactions-in-castle-activerecord.  In it, Ben Scheirman shows how to quickly create a new AR SessionScope object which effectively sets up an AR transaction, do my .Save, and then close the transaction, thus committing the write to the database. 

Using New Castle.ActiveRecord.SessionScope
    ...
    MyObject.Save()
End Using

I wasn’t sure if nesting transactions like this would work or would cause other problems, but after some additional testing it appears to do the job and no more.

Ship it!

Advertisements

November 29, 2010 - Posted by | Castle ActiveRecord

Sorry, the comment form is closed at this time.

%d bloggers like this: