Maarten Balliauw {blog}

ASP.NET MVC, Microsoft Azure, PHP, web development ...

NAVIGATION - SEARCH

NHibernate 1.2.0 - Unexpected row count: 0; expected: 1

Great... I've been working with NHibernate and MySQL for a while now, without having any strange problems. For a project I'm working on, I'm using SqlClient instead of MySQL now, and strangeness occurs. When I try to Flush() a NHibernate session, here's what is thrown:

Unexpected row count: 0; expected: 1
at NHibernate.AdoNet.Expectations.BasicExpectation.VerifyOutcomeNonBatched(Int32 rowCount, IDbCommand statement)
at NHibernate.Impl.NonBatchingBatcher.AddToBatch(IExpectation expectation)
at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)
at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Int32[] dirtyFields, Boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object obj, ISessionImplementor session)
at NHibernate.Impl.ScheduledUpdate.Execute()
at NHibernate.Impl.SessionImpl.Execute(IExecutable executable)
at NHibernate.Impl.SessionImpl.ExecuteAll(IList list)
at NHibernate.Impl.SessionImpl.Execute()
at NHibernate.Impl.SessionImpl.Flush()
at NHibernate.Transaction.AdoTransaction.Commit()

The problem seems to be a combination of things. First, there's my mapping file:

[code:xml]

<id name="Hash" column="hash_id" type="String">
<generator class="assigned"/>
</id>

[/code]

Second, I use _session.SaveOrUpdate(o). SaveOrUpdate() tries to use the NHibernate baked-in generator assigned in the mapping file (in my case: "assigned"). Since my Hash column is filled by hand, using a source-code algorithm, NHibernate can't re-assign the identifier column using the generator, resulting in the above error.

Solution: do NOT assign identifier columns, NHibernate will do this for you! The hash column was thus removed as an identifier, and a normal identifier column has been added. Resulting in a working piece of code. Here's the new mapping:

[code:xml]

<id name="Id" column="id" type="Guid">
<generator class="guid"/>
</id>
<property column="hash_id" type="String" name="Hash" not-null="true" length="50" />

[/code]

Enable sitemap security trimming in ASP.NET 2.0

Want to enable security trimming for your ASP.NET sitemap? Here's how...

First of all, you need a new section in your web.config system.web element:

[code:xml]

<system.web>
  <!-- ... other system.web configuration stuff ... -->
  <siteMap defaultProvider="XmlSiteMapProvider" enabled="true">
    <providers>
      <add name="XmlSiteMapProvider"
        description="Default SiteMap provider."
        type="System.Web.XmlSiteMapProvider "
        siteMapFile="Web.sitemap"
        securityTrimmingEnabled="true" />
    </providers>
  </siteMap>
</system.web>

[/code]

Next, you should specify which pages are visible to who:

[code:xml]

<location path="ForgotPassword.aspx">
  <system.web>
    <authorization>
      <allow users="?"/>
      <deny users="*"/>
    </authorization>
  </system.web>
</location>
<location path="ModifyPassword.aspx">
  <system.web>
    <authorization>
      <deny users="?"/>
      <allow users="*"/>
    </authorization>
  </system.web>
</location>

[/code]

In this example, the page ForgotPassword.aspx is visible to anonymous users, while authenticated users do not need this page (as they already knew their password while logging in...). ModifyPassword.aspx is only visible to authenticated users, as anonymous users can't do that.

Team Foundation Server - Subversion bridge

Tortoise SVNHere's the thing: for my private development work (a.k.a. PHPExcel 8-)), I've been using Subversion as my source-control server (and client). As the PHPExcel is hosted on CodePlex, one would suspect I would be using the Team Foundation hosted service which is provided for free. Not really... Here's the thing: CodePlex provides a web interface to work items, which me and my project members use a lot. But since one needs Visual Studio to use the TFS code repository in a comfortable way, without having to use any command-line tools, I decided to use Subversion as the source repository.

Some cool news:  the CodePlex people have released a TFS - SVN bridge, which is a man-in-the-middle proxy that translates (some) SVN command to TFS. This means anyone using SVN can now also use his (or her) tools to connect both to a Subversion server and a TFS server.

Update: I just spotted another TFS client written by Ben. It provides a lot of functionality similar to TortoiseSVN for Subversion, but does not use the proxy described above.