Thursday 2 September 2010

Forcing a build on when Visual Studios' Debugger starts

It been a while but boy have i been busy :/

Having read http://webproject.scottgu.com/CSharp/UserControls/UserControls.aspx and http://weblogs.asp.net/scottgu/archive/2005/08/28/423888.aspx and trying to implement it i found myself in a nasty situation concerning 2 problems. First of all when an error occurs on the markup side of a UserControl/Page/etc the debugger with show the error not on the file that exists on the external library but on the file that we copied in our Web Application/Site. Its quite easy when making very small changes to get confused and make the changes on the stale file. I haven't found a neat solution on this and unfortunately the solution with the embedded usercontrols didn't work for me. Maybe it has something to do with Visual Studio 2008


Secondly, and quite importantly, hitting F5 to fire up the debugger will not guarantee a build! The reason, at least with Web Applications, is that changes on markup files will do not mark the library as dirty. In fact, any "Content" file has the same effect. So changing some important bit that does not change any code file and then starting the debugger will not trigger a build and so, since we are using copy/paste deployment and this depends on the pre-build event, the actual file that the application will use is stale. I find it very funny that msdn's MVP's actually advise to do a manual build. Surely there must be a better way!


After some digging around i found that the user can tamper with Visual Studio's event via the Macro Designer.
The initial implementation used this code part http://www.mztools.com/articles/2007/mz2007020.aspx
but i soon found out that even when the debugger is running, when entering Content files the ide will change to designer mode. So after searching the various exposed events i made this little simple fragment

    Private _curDebugState As EnvDTE80.dbgProcessState

    Public Sub debuggerStateChangedHandler( _
        ByVal NewProcess As EnvDTE.Process, _
        ByVal processState As EnvDTE80.dbgProcessState) _
        Handles DebuggerProcessEvents.OnProcessStateChanged
        If _curDebugState = dbgProcessState.dbgProcessStateStop And processState = dbgProcessState.dbgProcessStateRun Then
            DTE.ExecuteCommand("Build.BuildSolution")
        End If
        _curDebugState = processState
    End Sub

There are of course other commands like Build.BuildSelection, Build.RebuildSolution so choose your preference and you're set!

Thursday 21 January 2010

Enabling Filters on mapped entities

I was trying to figure out if I could persuade NHibernate to enable filters on my <many-to-one /> entities and i fell on this discussion http://bit.ly/6W7WIA on the nhibernate-development google group. In short, <many-to-one /> filters should not work because filters where designed to filter data, not modify the domain.A valid viewpoint but i needed that functionality.


I have to think that filters should work out-of-the box and the developer should be responsible of enabling or disabling them. The reason is that i have a setup, that the represented domain can only reflected using filters. That is, applying WHERE clauses with dynamic parameters that are generated from the UI and that parameters remain the same for the length of the Request. As such the WHERE attribute on the class


Digging up the NH 2.1.2 source code i've found the single piece of code that is responsible for the behaviour.
Open up the NHibernate.Loader.Entity.EntityJoinWalker class and at approximately line 24 exists this piece of code:


SqlStringBuilder whereCondition = WhereString(Alias, uniqueKey, batchSize)
      //include the discriminator and class-level where, but not filters
      .Add(persister.FilterFragment(Alias, new CollectionHelper.EmptyMapClass<string, IFilter>()));
if you change it to

SqlStringBuilder whereCondition = WhereString(Alias, uniqueKey, batchSize)
       .Add(persister.FilterFragment(Alias, enabledFilters));

any enabled filters will be applied to your <many-to-one /> mapped entities as long as the filter exists on the entity definition mapping.

This little modification additionally enables filters for ISession.Get() and it works normally with lazy loading. If you are going to use ISession.Get() note that the cache is hit first before going to the datastore. In my setup, because the filter parameter defines a different entity instance for a given entity-id the second-level cache is not (and must not) be used, so take that into consideration before applying the modification to your solution.


I am thinking that if we could pass a parameter on the WHERE attribute on the class mapping (and ensure that this where fragment is used on ANSI-joins) none of this would have a reason to exist

Wednesday 20 January 2010

Many-to-one and Composite-id mapping with NHibernate

Nhibernate's reference documentation sometimes leaves something to be desired. I was looking for the correct syntax to map a which has a and the documentation did not discuss it and a google search revealed nothing. While poking around the 'nhibernate-mapping.xsd' i found out that the element supports having elements underneath it so as to have the following syntax


<many-to-one name="Foo">
  <column name="FK_Column1">
  <column name="FK_Column2">
</column>


where the Foo class is mapped as
<class name="Foo" table="Foo">
  <composite-id class="FooCompId">
    <key-many-to-one name="SomeEntityA" column="PK_Column1">
    <key-many-to-one name="SomeEntityB" column="PK_Column2">
  <composite-id>
  ....
</composite-id>


note here that the Foo class uses 2 properly mapped classes (SomeEntityA and SomeEntityB) hence the <key-many-to-one/>
interestingly i used this as part of a <subclass /> element and it worked normally.

And to map a <bag /> of "Foo" from an other entity this syntax worked

<bag name="Foos" inverse"true">
  <key>
    <column name="FK_Column1">
    <column name="FK_Column2">
  </key>
  <one-to-many class="Foo" />
</bag>

the only requirement is that the order of the columns declared must match the order of the <key-many-to-one/> declared in the composite-id