<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" version="2.0">
  <channel>
    <title>Manuel Abadia's ASP.NET stuff - NHibernate</title>
    <link>http://www.manuelabadia.com/blog/</link>
    <description />
    <language>en-us</language>
    <copyright>Manuel Abadia</copyright>
    <lastBuildDate>Fri, 01 Aug 2008 10:10:15 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 1.9.6264.0</generator>
    <managingEditor>blogcomments@manuelabadia.com</managingEditor>
    <webMaster>blogcomments@manuelabadia.com</webMaster>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=a93878c1-bd98-40d1-81cb-8bbfb6f0bb63</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=a93878c1-bd98-40d1-81cb-8bbfb6f0bb63</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
The changes from v1.2 to the current one (v2.0) are:
</p>
        <ul>
          <li>
Now using NHibernate 2.0.0 CR1.</li>
          <li>
Fixed a bug that caused the provider to look for the configuration settings only in
the nhibernate config section. If you configured NHibernate using the hibernate-configuration
section, it didn't work.</li>
          <li>
Fixed a bug that prevented hashed passwords to work without supplying a password answer.</li>
          <li>
Some code refactoring/clean up.</li>
          <li>
Removed all FXCop warnings.</li>
          <li>
Changed the mapping generation for the NHCustomMembershipProvider. In NHiberante 2.0.0
CR1, it is not possible to create mappings programatically as before, so now a xml
document with the mapping is created.</li>
          <li>
Fixed a bug in ChangePassword and ResetPassword methods that made the stored password
answer useless if the provider was using hashed format with password salt.</li>
        </ul>
        <p>
From some questions/emails I've got, it seems that some people aren't using
the provider the way it was designed. There is no need to modify the code in the provider
to support custom fields for your Users or Roles. I have created a sample that uses
all the fields in the membership provider and adds some custom fields to
show how the provider should be used. The sample also uses the CreateUserExWizard
control in order to create an user.
</p>
        <p>
As always, feedback is welcome. It has been tested only in SQL Server 2005. Let me
know if you try it in other databases. 
</p>
        <p>
The binaries and source code can be downloaded <a href="http://www.manuelabadia.com/blog/PermaLink,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx">here</a></p>
        <p>
 
</p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=a93878c1-bd98-40d1-81cb-8bbfb6f0bb63" />
      </body>
      <title>Update to my NHibernate Custom Membership and Role Providers</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx</link>
      <pubDate>Fri, 01 Aug 2008 10:10:15 GMT</pubDate>
      <description>&lt;p&gt;
The changes from v1.2 to the current one (v2.0) are:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Now using NHibernate 2.0.0 CR1.&lt;/li&gt;
&lt;li&gt;
Fixed a bug that caused the provider to look for the configuration settings only in
the nhibernate config section. If you configured NHibernate using the hibernate-configuration
section, it didn't work.&lt;/li&gt;
&lt;li&gt;
Fixed a bug that prevented hashed passwords to work without supplying a password answer.&lt;/li&gt;
&lt;li&gt;
Some code refactoring/clean up.&lt;/li&gt;
&lt;li&gt;
Removed all FXCop warnings.&lt;/li&gt;
&lt;li&gt;
Changed the mapping generation for the NHCustomMembershipProvider. In NHiberante 2.0.0
CR1, it is not possible to create mappings programatically as before, so now a xml
document with the mapping is created.&lt;/li&gt;
&lt;li&gt;
Fixed a bug in ChangePassword and ResetPassword methods that made the stored password
answer&amp;nbsp;useless if the provider was using hashed format with password salt.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
From some&amp;nbsp;questions/emails I've got,&amp;nbsp;it seems that some people aren't using
the provider the way it was designed. There is no need to modify the code in the provider
to support custom fields for your Users or Roles. I have created a sample that uses
all the fields in the&amp;nbsp;membership&amp;nbsp;provider and adds some custom fields to
show how the provider should be used. The sample also uses the CreateUserExWizard
control in order to create an user.
&lt;/p&gt;
&lt;p&gt;
As always, feedback is welcome. It has been tested only in SQL Server 2005. Let me
know if you try it in other databases. 
&lt;/p&gt;
&lt;p&gt;
The binaries and source code can be downloaded &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=a93878c1-bd98-40d1-81cb-8bbfb6f0bb63" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx</comments>
      <category>ASP.NET;NHibernate</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=a073bf47-5324-4884-9e2f-730fb8d78f7b</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,a073bf47-5324-4884-9e2f-730fb8d78f7b.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,a073bf47-5324-4884-9e2f-730fb8d78f7b.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=a073bf47-5324-4884-9e2f-730fb8d78f7b</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
One of the tools I’m using is NDepend (<a href="http://www.ndepend.com/">http://www.ndepend.com/</a>).
It is a cool application that can be used for a lot of things, as will be detailed
later. 
</p>
        <p>
To use NDepend you have to feed it with a set of assemblies. After that, it will analyze
those assemblies and their reference assemblies. If the PDBs of the assemblies are
available it will use them so more data is analyzed, although the PDBs are not needed
for NDepend to work.
</p>
        <p>
After the analysis has been completed, NDepend looks like this:
</p>
        <img src="http://www.manuelabadia.com/blog/content/binary/ndepend1.png" border="0" />
        <p>
          <br />
I have used version 1.1 of Spring.NET Framework (<a href="http://www.springframework.net/">http://www.springframework.net/</a>)
for the sample. As you can see the application has a beautiful GUI. I’ll talk a bit
about the main windows of the tool:
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
• Metrics: this window gives a graphical high level view of the project. You
can see a lot of ellipses and some of them that are made of smaller ellipses. The
big ellipses are types of the project. If a big ellipse is made of several smaller
ellipses, those smaller ellipses are the methods of the type. The types of the same
namespace are distributed in the same rectangular region, separated by a small yellow
line. The assemblies are separated by a thicker yellow line. 
</p>
          <p>
By watching this window you can get an idea of which assemblies contain more code,
which types are big, which types have a lot of methods, etc. The window was in “Method
Level”. The available levels are Assembly, Namespace, Type, Method and Field.
</p>
          <p>
• Class Browser: this is where the assemblies of the project and its referenced
assemblies are shown. You can expand the assembly up to the field level. While you
hover over an item in most windows, the Metrics window gets updated highlighting the
hovered item. 
</p>
          <p>
What it’s really cool about the Class Browser is that for the referenced assemblies,
only the namespaces, types, methods and other items that are used by the project are
shown.
</p>
          <p>
• Info: When you hover over an item the information about it is displayed here,
with some metrics if applicable. There are a lot of metrics so it can take time to
interiorize them and judge their value appropriately.
</p>
          <p>
• Dependencies: this window is a bit intimidating at first but like a lot of
things, with a bit of effort you can master it. The window displays very important
information of the dependencies in a matrix form. As in other windows, the detail
level is selectable, from the assembly level to the field level. 
</p>
          <p>
A cell can have 3 colors. Blue means that the associated item in the top header uses
the associated item in the left header. Green means that the associated item in the
left header is using the associated item in the top header. Black means a cyclic dependency.
The blue and green cells express the same dependency using opposite points of view. 
</p>
          <p>
You can see a diagram of the dependencies clicking on a cell. For example, if you
click in the cell corresponding to System.Web.Extensions and System.Web you get this:
</p>
          <img src="http://www.manuelabadia.com/blog/content/binary/BoxAndArrowGraph.PNG" border="0" />
          <p>
To read more about the theory of dependencies take a look here:
</p>
          <p>
            <a href="http://www.theserverside.net/tt/articles/showarticle.tss?id=ControllingDependencies">ttp://www.theserverside.net/tt/articles/showarticle.tss?id=ControllingDependencies</a>
          </p>
          <p>
• CQL Queries: CQL stands for Code Query Language and it is a central piece of
NDepend. Being able to ask questions about the code is great. If you like using the
Analyzer window in Reflector you’ll love this. You can create new queries and modify
the existing ones.
</p>
        </blockquote>
        <p dir="ltr">
I have presented the main NDepend windows, but the main question is: what you can
do with NDepend?
</p>
        <p dir="ltr">
There are several uses that I can think of:
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p dir="ltr">
• It is an excellent tool to check differences between different builds of an
assembly. You can use it as a diff tool, as it will show in the Class Browser which
types, methods, etc have been added, removed or changed. This information is also
available for CQL Queries, with the power that it implies.
</p>
          <p>
• It can be used to understand code. When you are thrown with code that you have
no clue about how it works you have several options to accomplish that task:
</p>
          <ol dir="ltr" style="MARGIN-RIGHT: 0px">
            <li>
Look at the source code directly. 
</li>
            <li>
Make some diagrams from the source code (for example, using View Class Diagram in
Visual Studio). 
</li>
            <li>
Use NDepend.</li>
          </ol>
          <p dir="ltr">
These methods are not exclusive, and probably you’ll use a combination of them to
understand how the code works. However, the abstraction level is higher when you use
NDepend is higher than when you use a Class Diagram (and a Class Diagram is a high
level view compared to raw source code).  I’d use NDepend to have a global vision
of the main assemblies, type most used, dependencies between namespaces, more complex
methods, etc. and then focus my attention in the most important parts of the application,
going to a lower level of detail.
</p>
          <p dir="ltr">
• It can be used in the refactoring process, to see the impact of a change, and
to keep dependencies to a minimum, in order to have a project that is easier to understand
and maintain.
</p>
          <p>
• Integrating NDepend in the software development process. IMHO this is a key
point, as using NDepend regulary will certainly improve the quality of the software
that is being developed.  NDepend can generate a report of a project. A sample
report is available here:
</p>
          <p>
            <a href="http://www.ndepend.com/SampleReports/OnNUnit/NDependReport.html">http://www.ndepend.com/SampleReports/OnNUnit/NDependReport.html</a>
          </p>
          <p>
There are a lot of sections in the report, but I’ll concentrate on the section called
“CQL Queries and Constraints”. That section is really important as it shows a list
of items that can be problematic or don’t follow the standards of your company (methods
with a lot of lines of code, very complex methods, poorly commented methods, types
or methods or properties or fields with incorrect naming conventions, etc). This way
the project leader can make periodic checks of those problems and report them to the
people that are responsible for them. 
<br />
This also allows you to know more the people you’re working with. Some developers
don’t comment code, others like to make very long methods, and others tend to write
complex logic that is difficult to understand by others. With the review of the report,
they can be instructed so the resulting code and comments is better and more uniform.
</p>
          <p>
However, there are times where a method with more than 30 lines of code is necessary.
Or a method with a cyclomatic complexity of 25 is needed. So it is up to the project
leader to review the suspicious method and inform the developers of the problem or
simply acknowledge that it is necessary. 
</p>
          <p>
Unfortunately, NDepend does not provide built in support for this level of detail
of project management. I have been told that in a future version it will provide hooks
so custom scenarios like the exposed above are fully supported.
</p>
        </blockquote>
        <p dir="ltr">
So, after what I have said about NDepend, you can be thinking, is it for me? Well,
that depends on a lot of factors. I know a lot of companies that have no interest
in achieving high quality products and that they only care about having a project
done as soon as possible. If the maintenance of that project is a nightmare, well,
that is another problem for another moment. However, there are some companies that
actually spend time and effort to produce excellent products, so they may be interested
in what NDepend can add for them.
</p>
        <p dir="ltr">
I have used NDepend in several projects that are widely used when learning about it,
and I found something curious:
</p>
        <p dir="ltr">
          <img src="http://www.manuelabadia.com/blog/content/binary/nhibernate_dependencies.png" border="0" />
        </p>
        <p dir="ltr">
The image shows that almost all of the NHibernate code has a big dependency cycle.
I wish them good luck making the transition to ASTs.
</p>
        <p dir="ltr">
          <em>To finish this post, I have to say that I have received a free professional version
of NDepend. This has not conditioned my post about it. If I think it was a useless
product I will not have posted about it.<br /></em>
        </p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=a073bf47-5324-4884-9e2f-730fb8d78f7b" />
      </body>
      <title>NDepend</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,a073bf47-5324-4884-9e2f-730fb8d78f7b.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,a073bf47-5324-4884-9e2f-730fb8d78f7b.aspx</link>
      <pubDate>Fri, 08 Feb 2008 12:22:13 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
One of the tools I’m using is NDepend (&lt;a href="http://www.ndepend.com/"&gt;http://www.ndepend.com/&lt;/a&gt;).
It is a cool application that can be used for a lot of things, as will be detailed
later. 
&lt;/p&gt;
&lt;p&gt;
To use NDepend you have to feed it with a set of assemblies. After that, it will analyze
those assemblies and their reference assemblies. If the PDBs of the assemblies are
available it will use them so more data is analyzed, although the PDBs are not needed
for NDepend to work.
&lt;/p&gt;
&lt;p&gt;
After the analysis has been completed, NDepend looks like this:
&lt;/p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/ndepend1.png" border=0&gt; 
&lt;p&gt;
&lt;br&gt;
I have used version 1.1 of Spring.NET Framework (&lt;a href="http://www.springframework.net/"&gt;http://www.springframework.net/&lt;/a&gt;)
for the sample. As you can see the application has a beautiful GUI. I’ll talk a bit
about the main windows of the tool:
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
•&amp;nbsp;Metrics: this window gives a graphical high level view of the project. You
can see a lot of ellipses and some of them that are made of smaller ellipses. The
big ellipses are types of the project. If a big ellipse is made of several smaller
ellipses, those smaller ellipses are the methods of the type. The types of the same
namespace are distributed in the same rectangular region, separated by a small yellow
line. The assemblies are separated by a thicker yellow line. 
&lt;/p&gt;
&lt;p&gt;
By watching this window you can get an idea of which assemblies contain more code,
which types are big, which types have a lot of methods, etc. The window was in “Method
Level”. The available levels are Assembly, Namespace, Type, Method and Field.
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;Class Browser: this is where the assemblies of the project and its referenced
assemblies are shown. You can expand the assembly up to the field level. While you
hover over an item in most windows, the Metrics window gets updated highlighting the
hovered item. 
&lt;/p&gt;
&lt;p&gt;
What it’s really cool about the Class Browser is that for the referenced assemblies,
only the namespaces, types, methods and other items that are used by the project are
shown.
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;Info: When you hover over an item the information about it is displayed here,
with some metrics if applicable. There are a lot of metrics so it can take time to
interiorize them and judge their value appropriately.
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;Dependencies: this window is a bit intimidating at first but like a lot of
things, with a bit of effort you can master it. The window displays very important
information of the dependencies in a matrix form. As in other windows, the detail
level is selectable, from the assembly level to the field level. 
&lt;/p&gt;
&lt;p&gt;
A cell can have 3 colors. Blue means that the associated item in the top header uses
the associated item in the left header. Green means that the associated item in the
left header is using the associated item in the top header. Black means a cyclic dependency.
The blue and green cells express the same dependency using opposite points of view. 
&lt;/p&gt;
&lt;p&gt;
You can see a diagram of the dependencies clicking on a cell. For example, if you
click in the cell corresponding to System.Web.Extensions and System.Web you get this:
&lt;/p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/BoxAndArrowGraph.PNG" border=0&gt; 
&lt;p&gt;
To read more about the theory of dependencies take a look here:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.theserverside.net/tt/articles/showarticle.tss?id=ControllingDependencies"&gt;ttp://www.theserverside.net/tt/articles/showarticle.tss?id=ControllingDependencies&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;CQL Queries: CQL stands for Code Query Language and it is a central piece of
NDepend. Being able to ask questions about the code is great. If you like using the
Analyzer window in Reflector you’ll love this. You can create new queries and modify
the existing ones.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
I have presented the main NDepend windows, but the main question is: what you can
do with NDepend?
&lt;/p&gt;
&lt;p dir=ltr&gt;
There are several uses that I can think of:
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p dir=ltr&gt;
•&amp;nbsp;It is an excellent tool to check differences between different builds of an
assembly. You can use it as a diff tool, as it will show in the Class Browser which
types, methods, etc have been added, removed or changed. This information is also
available for CQL Queries, with the power that it implies.
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;It can be used to understand code. When you are thrown with code that you have
no clue about how it works you have several options to accomplish that task:
&lt;/p&gt;
&lt;ol dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;li&gt;
Look at the source code directly. 
&lt;li&gt;
Make some diagrams from the source code (for example, using View Class Diagram in
Visual Studio). 
&lt;li&gt;
Use NDepend.&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=ltr&gt;
These methods are not exclusive, and probably you’ll use a combination of them to
understand how the code works. However, the abstraction level is higher when you use
NDepend is higher than when you use a Class Diagram (and a Class Diagram is a high
level view compared to raw source code).&amp;nbsp; I’d use NDepend to have a global vision
of the main assemblies, type most used, dependencies between namespaces, more complex
methods, etc. and then focus my attention in the most important parts of the application,
going to a lower level of detail.
&lt;/p&gt;
&lt;p dir=ltr&gt;
•&amp;nbsp;It can be used in the refactoring process, to see the impact of a change, and
to keep dependencies to a minimum, in order to have a project that is easier to understand
and maintain.
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;Integrating NDepend in the software development process. IMHO this is a key
point, as using NDepend regulary will certainly improve the quality of the software
that is being developed.&amp;nbsp; NDepend can generate a report of a project. A sample
report is available here:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.ndepend.com/SampleReports/OnNUnit/NDependReport.html"&gt;http://www.ndepend.com/SampleReports/OnNUnit/NDependReport.html&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
There are a lot of sections in the report, but I’ll concentrate on the section called
“CQL Queries and Constraints”. That section is really important as it shows a list
of items that can be problematic or don’t follow the standards of your company (methods
with a lot of lines of code, very complex methods, poorly commented methods, types
or methods or properties or fields with incorrect naming conventions, etc). This way
the project leader can make periodic checks of those problems and report them to the
people that are responsible for them. 
&lt;br&gt;
This also allows you to know more the people you’re working with. Some developers
don’t comment code, others like to make very long methods, and others tend to write
complex logic that is difficult to understand by others. With the review of the report,
they can be instructed so the resulting code and comments is better and more uniform.
&lt;/p&gt;
&lt;p&gt;
However, there are times where a method with more than 30 lines of code is necessary.
Or a method with a cyclomatic complexity of 25 is needed. So it is up to the project
leader to review the suspicious method and inform the developers of the problem or
simply acknowledge that it is necessary. 
&lt;/p&gt;
&lt;p&gt;
Unfortunately, NDepend does not provide built in support for this level of detail
of project management. I have been told that in a future version it will provide hooks
so custom scenarios like the exposed above are fully supported.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
So, after what I have said about NDepend, you can be thinking, is it for me? Well,
that depends on a lot of factors. I know a lot of companies that have no interest
in achieving high quality products and that they only care about having a project
done as soon as possible. If the maintenance of that project is a nightmare, well,
that is another problem for another moment. However, there are some companies that
actually spend time and effort to produce excellent products, so they may be interested
in what NDepend can add for them.
&lt;/p&gt;
&lt;p dir=ltr&gt;
I have used NDepend in several projects that are widely used when learning about it,
and I found something curious:
&lt;/p&gt;
&lt;p dir=ltr&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/nhibernate_dependencies.png" border=0&gt;
&lt;/p&gt;
&lt;p dir=ltr&gt;
The image shows that almost all of the NHibernate code has a big dependency cycle.
I wish them good luck making the transition to ASTs.
&lt;/p&gt;
&lt;p dir=ltr&gt;
&lt;em&gt;To finish this post, I have to say that I have received a free professional version
of NDepend. This has not conditioned my post about it. If I think it was a useless
product I will not have posted about it.&lt;br&gt;
&lt;/em&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=a073bf47-5324-4884-9e2f-730fb8d78f7b" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,a073bf47-5324-4884-9e2f-730fb8d78f7b.aspx</comments>
      <category>ASP.NET;Microsoft .NET Framework;NHibernate</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=27e22b2c-af95-4f4c-befd-1debc5841735</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,27e22b2c-af95-4f4c-befd-1debc5841735.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,27e22b2c-af95-4f4c-befd-1debc5841735.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=27e22b2c-af95-4f4c-befd-1debc5841735</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Due to lack of time I haven’t been able to make a sample website showing a complete
usage scenario for my NHibernate custom Membership and Role providers. However, as
there are nearly 100 downloads per month and there is some people using it I’m uploading
a new version. The changes from the latest release are:
</p>
        <ul dir="ltr">
          <li>
            <div style="MARGIN-RIGHT: 0px">Fixed an important bug that didn’t prevent locked out
users from login in.
</div>
          </li>
          <li>
            <div style="MARGIN-RIGHT: 0px">Added a CreateUserWizardEx control that allows creating
a user with extra information in an easy way.
</div>
          </li>
          <li>
            <div style="MARGIN-RIGHT: 0px">Added auto unlock support.
</div>
          </li>
          <li>
            <div style="MARGIN-RIGHT: 0px">Fixed some minor bugs/typos.
</div>
          </li>
        </ul>
        <p>
I’ll detail a bit the new features. The standard CreateUserWizard control generates
an event before creating the user (CreatingUser) and one after the user has been created
(CreatedUser). Somewhere between these two events the control calls the CreateUser
method of the membership provider. The CreateUserWizardEx control extends the CreateUserWizard
that ship with ASP.NET 2.0. It is supposed to be used when you want to insert a user
in the system without using the CreateUser method of the membership provider (for
example, because you want to store more data in the database).<br />
 <br />
The CreateUserWizardEx control adds a CreateUserEx event. You should handle this event,
retrieve all the information for the new user and make the insert in your users table
manually (as the provider interface can’t handle extra data). This event will be generated
after all the password checking and generation have been made, so you only have to
insert the user in the database. When you handle this event, you’ll be passed an instance
of the CreateUserExEventArgs class. This class has 3 properties: EncodedPassword,
EncodedPasswordSalt and EncodedPasswordAnswer that are useful if you’re not storing
the sensitive data in plain text. After the CreateUserEx event is generated, the CreatedUser
event is also generated.
</p>
        <p>
There is one little problem with the CreateUserWizardEx control. Because quite a bit
ASP.NET classes (especially controls) haven’t been designed with extensibility in
mind, it is impossible to override some of the behavior of the CreateUserWizard control
to achieve the desired result. In this particular case I can’t make the control to
skip the CreateUser call to the membership provider in any way without rewriting the
full control (the CreateUserWizard is one of the lengthiest controls in ASP.NET this
is not an option). So the only solution without compromising medium trust scenarios
is to ignore the CreateUser method calls in case you plan to insert the users manually.
To do this you have to set the provider attribute ignoreCreateUserMethod to true.
If the CreateUserWizard control is ever rewritten with extensibility in mind this
hack could be removed, but I don’t think that will happen anytime. I posted about
similar lack of extensibility problems here.
</p>
        <p>
The auto unlock feature is useful if you use locking. If a user fails entering the
password several times in a predefined period of time (specified by the maxInvalidPasswordAttempts
and passwordAttemptWindow properties) his account gets locked out. However, you need
human interaction in order to unlock the user.
</p>
        <p>
If the auto unlock feature is enabled, when a locked user tries to log on the system,
if the data supplied is correct and a certain period of time has passed since the
account was locked out, the provider automatically unlocks the account. To enable
auto unlocking you have to specify enableAutoUnlock="true" in the web.config. The
provider property autoUnlockMinutes controls the minium period of time to wait since
the last failed login to be able to auto unlock an account. The default is 30 minutes.
Note that setting this value too low can make the security benefits of having a lockout
feature disappear.
</p>
        <p>
I’m thinking in adding some code to enforce single user log on for the next version
as time permits (don’t expect this to be implemented in 2007).
</p>
        <p>
As always, feedback is welcome. As the previous version, it has been tested only in
SQL Server 2005. Let me know if you try it in other databases. 
</p>
        <p>
You can <a href="http://www.manuelabadia.com/blog/PermaLink,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx">download
the providers here</a>.
</p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=27e22b2c-af95-4f4c-befd-1debc5841735" />
      </body>
      <title>Custom Membership and Role Providers using NHibernate Update</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,27e22b2c-af95-4f4c-befd-1debc5841735.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,27e22b2c-af95-4f4c-befd-1debc5841735.aspx</link>
      <pubDate>Fri, 12 Oct 2007 14:58:30 GMT</pubDate>
      <description>&lt;p&gt;
Due to lack of time I haven’t been able to make a sample website showing a complete
usage scenario for my NHibernate custom Membership and Role providers. However, as
there are nearly 100 downloads per month and there is some people using it I’m uploading
a new version. The changes from the latest release are:
&lt;/p&gt;
&lt;ul dir=ltr&gt;
&lt;li&gt;
&lt;div style="MARGIN-RIGHT: 0px"&gt;Fixed an important bug that didn’t prevent locked out
users from login in.
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div style="MARGIN-RIGHT: 0px"&gt;Added a CreateUserWizardEx control that allows creating
a user with extra information in an easy way.
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div style="MARGIN-RIGHT: 0px"&gt;Added auto unlock support.
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div style="MARGIN-RIGHT: 0px"&gt;Fixed some minor bugs/typos.
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
I’ll detail a bit the new features. The standard CreateUserWizard control generates
an event before creating the user (CreatingUser) and one after the user has been created
(CreatedUser). Somewhere between these two events the control calls the CreateUser
method of the membership provider. The CreateUserWizardEx control extends the CreateUserWizard
that ship with ASP.NET 2.0. It is supposed to be used when you want to insert a user
in the system without using the CreateUser method of the membership provider (for
example, because you want to store more data in the database).&lt;br&gt;
&amp;nbsp;&lt;br&gt;
The CreateUserWizardEx control adds a CreateUserEx event. You should handle this event,
retrieve all the information for the new user and make the insert in your users table
manually (as the provider interface can’t handle extra data). This event will be generated
after all the password checking and generation have been made, so you only have to
insert the user in the database. When you handle this event, you’ll be passed an instance
of the CreateUserExEventArgs class. This class has 3 properties: EncodedPassword,
EncodedPasswordSalt and EncodedPasswordAnswer that are useful if you’re not storing
the sensitive data in plain text. After the CreateUserEx event is generated, the CreatedUser
event is also generated.
&lt;/p&gt;
&lt;p&gt;
There is one little problem with the CreateUserWizardEx control. Because quite a bit
ASP.NET classes (especially controls) haven’t been designed with extensibility in
mind, it is impossible to override some of the behavior of the CreateUserWizard control
to achieve the desired result. In this particular case I can’t make the control to
skip the CreateUser call to the membership provider in any way without rewriting the
full control (the CreateUserWizard is one of the lengthiest controls in ASP.NET this
is not an option). So the only solution without compromising medium trust scenarios
is to ignore the CreateUser method calls in case you plan to insert the users manually.
To do this you have to set the provider attribute ignoreCreateUserMethod to true.
If the CreateUserWizard control is ever rewritten with extensibility in mind this
hack could be removed, but I don’t think that will happen anytime. I posted about
similar lack of extensibility problems here.
&lt;/p&gt;
&lt;p&gt;
The auto unlock feature is useful if you use locking. If a user fails entering the
password several times in a predefined period of time (specified by the maxInvalidPasswordAttempts
and passwordAttemptWindow properties) his account gets locked out. However, you need
human interaction in order to unlock the user.
&lt;/p&gt;
&lt;p&gt;
If the auto unlock feature is enabled, when a locked user tries to log on the system,
if the data supplied is correct and a certain period of time has passed since the
account was locked out, the provider automatically unlocks the account. To enable
auto unlocking you have to specify enableAutoUnlock="true" in the web.config. The
provider property autoUnlockMinutes controls the minium period of time to wait since
the last failed login to be able to auto unlock an account. The default is 30 minutes.
Note that setting this value too low can make the security benefits of having a lockout
feature disappear.
&lt;/p&gt;
&lt;p&gt;
I’m thinking in adding some code to enforce single user log on for the next version
as time permits (don’t expect this to be implemented in 2007).
&lt;/p&gt;
&lt;p&gt;
As always, feedback is welcome. As the previous version, it has been tested only in
SQL Server 2005. Let me know if you try it in other databases. 
&lt;/p&gt;
&lt;p&gt;
You can &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx"&gt;download
the providers here&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=27e22b2c-af95-4f4c-befd-1debc5841735" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,27e22b2c-af95-4f4c-befd-1debc5841735.aspx</comments>
      <category>ASP.NET;Microsoft .NET Framework;NHibernate</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=736ddc0b-dc70-492f-aeff-ba09ebdeb511</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,736ddc0b-dc70-492f-aeff-ba09ebdeb511.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,736ddc0b-dc70-492f-aeff-ba09ebdeb511.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=736ddc0b-dc70-492f-aeff-ba09ebdeb511</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://www.ayende.com">Ayende</a> has <a href="http://ayende.com/Blog/archive/2007/09/29/NHibernate-ndash-not-all-that-glitters-is-gold.aspx">apologized</a> for
the way he resolved a <a href="http://jira.nhibernate.org/browse/NH-1123">NHibernate
bug</a> I reported. I’m glad he has changed his mind. I feel a lot of respect for
people that can admit a mistake.<br />
 <br />
He also <a href="http://ayende.com/Blog/archive/2007/09/29/NHibernate-ndash-not-all-that-glitters-is-gold.aspx">commented </a>about
the <a href="http://www.manuelabadia.com/blog/PermaLink,guid,ddd906d7-c5bd-44c0-b9c4-444bbbdf47fb.aspx">NHibernate
limitations I pointed out</a>. As he knows what the NHibernate team is working or
is planning to work on, it is a very interesting read.<br />
 <br />
Regarding points 2 (old design) and 5 (hierarchical queries), it seems that they’re
planning to make manipulations at the AST level, leaving the SQL generation as late
as possible. This seems as a very powerful change so I hope to see that change flowing
through the core to improve things.
</p>
        <p>
It seems that point 3 (more events in IInterceptor) will be addressed by some changes
that are being performed by Fabio Maulo. Cool!
</p>
        <p>
I think I was wrong with point 1 (being too tied to the Java version) as Ayende explains.<br />
 <br />
Regarding point 4 (no paging support in some nontrivial scenarios), I think that paging
when you retrieve an associated relationship eagerly should be supported. However,
if the subselect problem is fixed (so not all rows from the association are retrieved),
that certainly makes it less important. I was also referring to the limited paging
support for SQL Server 2000. However, I’m lucky to not be using SQL Server 2000 anymore…
</p>
        <p>
To sum up, the things the NHibernate team is planning for the future have made my
NHibernate interest grow up a lot since my rant about it.
</p>
        <p>
Ayende also mentions to try to fix bugs when you found one. I can’t agree more, however,
in my personal case, I have to spend about 3 hours a day to make exercises for my
back in order to be able to work with the computer without too much pain. That means
that my free time is really limited and probably away from the computer :-(
</p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=736ddc0b-dc70-492f-aeff-ba09ebdeb511" />
      </body>
      <title>NHibernate –not all that glitters is gold (continued)</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,736ddc0b-dc70-492f-aeff-ba09ebdeb511.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,736ddc0b-dc70-492f-aeff-ba09ebdeb511.aspx</link>
      <pubDate>Sat, 29 Sep 2007 23:25:30 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://www.ayende.com"&gt;Ayende&lt;/a&gt; has &lt;a href="http://ayende.com/Blog/archive/2007/09/29/NHibernate-ndash-not-all-that-glitters-is-gold.aspx"&gt;apologized&lt;/a&gt; for
the way he resolved a &lt;a href="http://jira.nhibernate.org/browse/NH-1123"&gt;NHibernate
bug&lt;/a&gt; I reported. I’m glad he has changed his mind. I feel a lot of respect for
people that can admit a mistake.&lt;br&gt;
&amp;nbsp;&lt;br&gt;
He also &lt;a href="http://ayende.com/Blog/archive/2007/09/29/NHibernate-ndash-not-all-that-glitters-is-gold.aspx"&gt;commented &lt;/a&gt;about
the &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,ddd906d7-c5bd-44c0-b9c4-444bbbdf47fb.aspx"&gt;NHibernate
limitations I pointed out&lt;/a&gt;. As he knows what the NHibernate team is working or
is planning to work on, it is a very interesting read.&lt;br&gt;
&amp;nbsp;&lt;br&gt;
Regarding points 2 (old design) and 5 (hierarchical queries), it seems that they’re
planning to make manipulations at the AST level, leaving the SQL generation as late
as possible. This seems as a very powerful change so I hope to see that change flowing
through the core to improve things.
&lt;/p&gt;
&lt;p&gt;
It seems that point 3 (more events in IInterceptor) will be addressed by some changes
that are being performed by Fabio Maulo. Cool!
&lt;/p&gt;
&lt;p&gt;
I think I was wrong with point 1 (being too tied to the Java version) as Ayende explains.&lt;br&gt;
&amp;nbsp;&lt;br&gt;
Regarding point 4 (no paging support in some nontrivial scenarios), I think that paging
when you retrieve an associated relationship eagerly should be supported. However,
if the subselect problem is fixed (so not all rows from the association are retrieved),
that certainly makes it less important. I was also referring to the limited paging
support for SQL Server 2000. However, I’m lucky to not be using SQL Server 2000 anymore…
&lt;/p&gt;
&lt;p&gt;
To sum up, the things the NHibernate team is planning for the future have made my
NHibernate interest grow up a lot since my rant about it.
&lt;/p&gt;
&lt;p&gt;
Ayende also mentions to try to fix bugs when you found one. I can’t agree more, however,
in my personal case, I have to spend about 3 hours a day to make exercises for my
back in order to be able to work with the computer without too much pain. That means
that my free time is really limited and probably away from the computer :-(
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=736ddc0b-dc70-492f-aeff-ba09ebdeb511" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,736ddc0b-dc70-492f-aeff-ba09ebdeb511.aspx</comments>
      <category>NHibernate</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=ddd906d7-c5bd-44c0-b9c4-444bbbdf47fb</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,ddd906d7-c5bd-44c0-b9c4-444bbbdf47fb.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,ddd906d7-c5bd-44c0-b9c4-444bbbdf47fb.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=ddd906d7-c5bd-44c0-b9c4-444bbbdf47fb</wfw:commentRss>
      <slash:comments>5</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
NHibernate is a popular and free ORM tool. It is based on the java version, called
Hibernate, which is also very popular in the Java world.
</p>
        <p>
However, NHibernate (I’m talking about version 1.2.0 GA here) has some limitations.
Some of them that are in the top of my head at the moment:
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
1) It is heavily tied to the java version (Hiberante), so a lot of the request
and/or enhancements are ignored. If the java version is not going to add it, probably
it will not be added to NHibernate.<br />
2) Hibernate was started in 2001, and was designed to overcome a lot of the ORM
problems. During these years, it has solved a lot of those problems, but other still
remain and they can’t be fixed without heavily changing its design.<br />
3) Even if it is extensible, the IInterceptor interface does not expose all the
events that can be interesting to capture (For example, events after loading, updating
or deleting data). The only way to handle that at the moment is to implement the ILifecycle
interface by the entity itself, losing entity transparency.<br />
4) No paging support in some nontrivial scenarios.<br />
5) There is no support for retrieving all the data at once for hierarchical queries.
</p>
        </blockquote>
        <p>
Let’s see a simple example:
</p>
        <p>
Imagine that I have some orders with their respective order items. I want a customer
to be able to see all orders he has placed on the system, with their associated order
items. As a customer can have a lot of orders, only 10 orders will be displayed per
page.
</p>
        <p>
ISession session = SessionFactory.OpenSession(); 
<br />
ICriteria criteria = session.CreateCriteria(typeof(MyOrder)); 
<br />
criteria.SetFirstResult(0); 
<br />
criteria.SetMaxResults(10); 
<br />
criteria.AddOrder(new Order("Id", true)); 
<br />
IList&lt;MyOrder&gt; orders = criteria.List&lt;MyOrder&gt;(); 
</p>
        <p>
Using <strong>lazy fetch</strong> mode, NHibernate does:
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
Gets the first 10 orders using a single select statement.
</p>
          <p>
Gets the order items for the first 10 orders using one select statement for each order.
</p>
        </blockquote>
        <p>
Using <strong>subselect</strong> mode, NHibernate does:
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
Gets the first 10 orders using a single select statement.
</p>
          <p>
Gets the order items for <strong>ALL</strong> the orders using a single select statement.
</p>
        </blockquote>
        <p>
To clearly see what NHibernate does when using the <strong>join</strong> (eager fetch)
mode, imagine that all orders have 3 order items. 
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
In that case, what NHiberante does is a left outer join of the order and orderitems
table, returning the first 10 rows of that join. That means that NHibernate returns
only 4 orders, the first three with 3 order items each one, and the last one only
with one order item. Take a look at the code, I was asking for 10 orders, and only
got 4, and the fourth is not filled with its three order items, only with one!
</p>
        </blockquote>
        <p>
I added this as a bug in the NHibernate bug tracker, and I received a quick reply
of its main developer, Sergey Koshcheyev, confirming me that NHibernate wasn’t able
to perform that query right because of the inner join, and didn’t know if it should
raise an error in that case or not. Nearly the same time Ayende Rahien closed the
case because that was the “expected behavior” because that is what is happening on
the DB side and that there wasn’t any way to get the data I was asking for.
</p>
        <p>
That response is completely wrong:
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
1) I’m asking NHibernate to get 10 orders and specifying a fetch strategy so
what I should get is 10 orders. Depending on the fetch strategy NHibernate may perform
one select, several selects, a join or whatever it needs to, but at least I expect
to get 10 orders (if there are present in the database table).
</p>
          <p>
2) It is possible to retrieve the proper data, and I added an example of how
to do it in the bug report.  If NHibernate can’t handle it, that is another
story…
</p>
        </blockquote>
        <p>
You can take a look at my bug report and its resolution here and decide yourself if
this was a good resolution or not:
</p>
        <p>
          <a href="http://jira.nhibernate.org/browse/NH-1123">http://jira.nhibernate.org/browse/NH-1123</a>
        </p>
        <p>
If you have read Ayende’s blog you'll know that he has complained several times about
how Microsoft Connects resolve some bugs (I agree that he is right and that they should
be fixed), but after his bug resolution, it seems a bit ironical to see him complaining
about that…
</p>
        <p>
I see NHibernate as a great product (and free) but as its codebase was started in
2001, it has get old. I will continue to use it but I’m evaluating other alternatives
(any suggestions (even if they are not free)?).
</p>
        <p>
Searching out there, I found a project that has really impressed me: <strong>SqlAlchemy</strong>.
This is the philosophy of the project:
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <em>SQL databases behave less and less like object collections the more size and performance
start to matter; object collections behave less and less like tables and rows the
more abstraction starts to matter. SQLAlchemy aims to accommodate both of these principles.</em>
          </p>
          <p>
            <em>SQLAlchemy doesn't view databases as just collections of tables; it sees them
as relational algebra engines. Its object relational mapper enables classes to be
mapped against the database in more than one way. SQL constructs don't just select
from just tables—you can also select from joins, subqueries, and unions. Thus database
relationships and domain object models can be cleanly decoupled from the beginning,
allowing both sides to develop to their full potential.</em>
          </p>
        </blockquote>
        <p>
SqlAlchemy first release was in 2006. <strong>The first version did support
what Nhibernate is not able to do</strong>:
</p>
        <p>
          <a href="http://www.sqlalchemy.org/docs/03/adv_datamapping.html#advdatamapping_limits">http://www.sqlalchemy.org/docs/03/adv_datamapping.html#advdatamapping_limits</a>
        </p>
        <p>
So it seems that it is possible after all…
</p>
        <p>
I’m very impressed with SqlAlchemy. However, SqlAlchemy currently is only available
for python. I hope it works properly with IronPython 2.0 (whenever it is released).
Although a C# version using C# 3.0 features would be a killer.
</p>
        <p>
You can see an example of the power of SqlAlchemy here:
</p>
        <p>
          <a href="http://spyced.blogspot.com/2007/01/why-sqlalchemy-impresses-me.html">http://spyced.blogspot.com/2007/01/why-sqlalchemy-impresses-me.html</a>
        </p>
        <p>
For more information about SqlAlchemy visit:
</p>
        <p>
          <a href="http://www.sqlalchemy.org/">http://www.sqlalchemy.org/</a>
        </p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=ddd906d7-c5bd-44c0-b9c4-444bbbdf47fb" />
      </body>
      <title>NHibernate – not all that glitters is gold</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,ddd906d7-c5bd-44c0-b9c4-444bbbdf47fb.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,ddd906d7-c5bd-44c0-b9c4-444bbbdf47fb.aspx</link>
      <pubDate>Mon, 24 Sep 2007 09:14:32 GMT</pubDate>
      <description>&lt;p&gt;
NHibernate is a popular and free ORM tool. It is based on the java version, called
Hibernate, which is also very popular in the Java world.
&lt;/p&gt;
&lt;p&gt;
However, NHibernate (I’m talking about version 1.2.0 GA here) has some limitations.
Some of them that are in the top of my head at the moment:
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
1)&amp;nbsp;It is heavily tied to the java version (Hiberante), so a lot of the request
and/or enhancements are ignored. If the java version is not going to add it, probably
it will not be added to NHibernate.&lt;br&gt;
2)&amp;nbsp;Hibernate was started in 2001, and was designed to overcome a lot of the ORM
problems. During these years, it has solved a lot of those problems, but other still
remain and they can’t be fixed without heavily changing its design.&lt;br&gt;
3)&amp;nbsp;Even if it is extensible, the IInterceptor interface does not expose all the
events that can be interesting to capture (For example, events after loading, updating
or deleting data). The only way to handle that at the moment is to implement the ILifecycle
interface by the entity itself, losing entity transparency.&lt;br&gt;
4)&amp;nbsp;No paging support in some nontrivial scenarios.&lt;br&gt;
5)&amp;nbsp;There is no support for retrieving all the data at once for hierarchical queries.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Let’s see a simple example:
&lt;/p&gt;
&lt;p&gt;
Imagine that I have some orders with their respective order items. I want a customer
to be able to see all orders he has placed on the system, with their associated order
items. As a customer can have a lot of orders, only 10 orders will be displayed per
page.
&lt;/p&gt;
&lt;p&gt;
ISession session = SessionFactory.OpenSession(); 
&lt;br&gt;
ICriteria criteria = session.CreateCriteria(typeof(MyOrder)); 
&lt;br&gt;
criteria.SetFirstResult(0); 
&lt;br&gt;
criteria.SetMaxResults(10); 
&lt;br&gt;
criteria.AddOrder(new Order("Id", true)); 
&lt;br&gt;
IList&amp;lt;MyOrder&amp;gt; orders = criteria.List&amp;lt;MyOrder&amp;gt;(); 
&lt;/p&gt;
&lt;p&gt;
Using &lt;strong&gt;lazy fetch&lt;/strong&gt; mode, NHibernate does:
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
Gets the first 10 orders using a single select statement.
&lt;/p&gt;
&lt;p&gt;
Gets the order items for the first 10 orders using one select statement for each order.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Using &lt;strong&gt;subselect&lt;/strong&gt; mode, NHibernate does:
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
Gets the first 10 orders using a single select statement.
&lt;/p&gt;
&lt;p&gt;
Gets the order items for &lt;strong&gt;ALL&lt;/strong&gt; the orders using a single select statement.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
To clearly see what NHibernate does when using the &lt;strong&gt;join&lt;/strong&gt; (eager fetch)
mode, imagine that all orders have 3 order items. 
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
In that case, what NHiberante does is a left outer join of the order and orderitems
table, returning the first 10 rows of that join. That means that NHibernate returns
only 4 orders, the first three with 3 order items each one, and the last one only
with one order item. Take a look at the code, I was asking for 10 orders, and only
got 4, and the fourth is not filled with its three order items, only with one!
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
I added this as a bug in the NHibernate bug tracker, and I received a quick reply
of its main developer, Sergey Koshcheyev, confirming me that NHibernate wasn’t able
to perform that query right because of the inner join, and didn’t know if it should
raise an error in that case or not. Nearly the same time Ayende Rahien closed the
case because that was the “expected behavior” because that is what is happening on
the DB side and that there wasn’t any way to get the data I was asking for.
&lt;/p&gt;
&lt;p&gt;
That response is completely wrong:
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
1)&amp;nbsp;I’m asking NHibernate to get 10 orders and specifying a fetch strategy so
what I should get is 10 orders. Depending on the fetch strategy NHibernate may perform
one select, several selects, a join or whatever it needs to, but at least I expect
to get 10 orders (if there are present in the database table).
&lt;/p&gt;
&lt;p&gt;
2)&amp;nbsp;It is possible to retrieve the proper data, and I added an example of how
to do it in the bug report.&amp;nbsp; If NHibernate can’t handle it,&amp;nbsp;that is another
story…
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
You can take a look at my bug report and its resolution here and decide yourself if
this was a good resolution or not:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://jira.nhibernate.org/browse/NH-1123"&gt;http://jira.nhibernate.org/browse/NH-1123&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
If you have read Ayende’s blog you'll know that he has complained several times about
how Microsoft Connects resolve some bugs (I agree that he is right and that they should
be fixed), but after his bug resolution, it seems a bit ironical to see him complaining
about that…
&lt;/p&gt;
&lt;p&gt;
I see NHibernate as a great product (and free) but as its codebase was started in
2001, it has get old. I will continue to use it but I’m evaluating other alternatives
(any suggestions (even if they are not free)?).
&lt;/p&gt;
&lt;p&gt;
Searching out there, I found a project that has really impressed me: &lt;strong&gt;SqlAlchemy&lt;/strong&gt;.
This is the philosophy of the project:
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;em&gt;SQL databases behave less and less like object collections the more size and performance
start to matter; object collections behave less and less like tables and rows the
more abstraction starts to matter. SQLAlchemy aims to accommodate both of these principles.&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;SQLAlchemy doesn't view databases as just collections of tables; it sees them
as relational algebra engines. Its object relational mapper enables classes to be
mapped against the database in more than one way. SQL constructs don't just select
from just tables—you can also select from joins, subqueries, and unions. Thus database
relationships and domain object models can be cleanly decoupled from the beginning,
allowing both sides to develop to their full potential.&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
SqlAlchemy&amp;nbsp;first release was in 2006. &lt;strong&gt;The first version&amp;nbsp;did support
what Nhibernate is not able to do&lt;/strong&gt;:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.sqlalchemy.org/docs/03/adv_datamapping.html#advdatamapping_limits"&gt;http://www.sqlalchemy.org/docs/03/adv_datamapping.html#advdatamapping_limits&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
So it seems that it is possible after all…
&lt;/p&gt;
&lt;p&gt;
I’m very impressed with SqlAlchemy. However, SqlAlchemy currently is only available
for python. I hope it works properly with IronPython 2.0 (whenever it is released).
Although a C# version using C# 3.0 features would be a killer.
&lt;/p&gt;
&lt;p&gt;
You can see an example of the power of SqlAlchemy here:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://spyced.blogspot.com/2007/01/why-sqlalchemy-impresses-me.html"&gt;http://spyced.blogspot.com/2007/01/why-sqlalchemy-impresses-me.html&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
For more information about SqlAlchemy visit:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.sqlalchemy.org/"&gt;http://www.sqlalchemy.org/&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=ddd906d7-c5bd-44c0-b9c4-444bbbdf47fb" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,ddd906d7-c5bd-44c0-b9c4-444bbbdf47fb.aspx</comments>
      <category>NHibernate</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=b169ef19-7123-4ab9-8724-36583bc7c16f</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,b169ef19-7123-4ab9-8724-36583bc7c16f.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,b169ef19-7123-4ab9-8724-36583bc7c16f.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=b169ef19-7123-4ab9-8724-36583bc7c16f</wfw:commentRss>
      <title>NHibernate and calculated properties</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,b169ef19-7123-4ab9-8724-36583bc7c16f.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,b169ef19-7123-4ab9-8724-36583bc7c16f.aspx</link>
      <pubDate>Tue, 11 Sep 2007 13:23:49 GMT</pubDate>
      <description>&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;I was optimizing an application
that uses NHibernate. This application has some special requirements, and for a few
classes, some of its properties are just complex calculations that use other properties.
Those calculations cannot be performed using formulas at the database level; they
have to be performed by the class. A simplified example is:&lt;/span&gt;
&lt;/p&gt;
&lt;div class=cf&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;System&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;System&lt;/span&gt;.&lt;span class=cb2&gt;Collections&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;System&lt;/span&gt;.&lt;span class=cb2&gt;Collections&lt;/span&gt;.&lt;span class=cb2&gt;Generic&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;System&lt;/span&gt;.&lt;span class=cb2&gt;Text&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;NHibernateUtil&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;NHibernate&lt;/span&gt;.&lt;span class=cb2&gt;Classic&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;namespace&lt;/span&gt; &lt;span class=cb2&gt;Sample&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
{
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;class&lt;/span&gt; &lt;span class=cb5&gt;Item&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;private&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;_id&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;private&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;_value1&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;private&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;_value2&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;private&lt;/span&gt; &lt;span class=cb1&gt;decimal&lt;/span&gt; &lt;span class=cb2&gt;_result&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;virtual&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;Id&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;get&lt;/span&gt; { &lt;span class=cb1&gt;return&lt;/span&gt; &lt;span class=cb2&gt;_id&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;set&lt;/span&gt; { &lt;span class=cb2&gt;_id&lt;/span&gt; = &lt;span class=cb1&gt;value&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;virtual&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;Value1&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;get&lt;/span&gt; { &lt;span class=cb1&gt;return&lt;/span&gt; &lt;span class=cb2&gt;_value1&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;set&lt;/span&gt; { &lt;span class=cb2&gt;_value1&lt;/span&gt; = &lt;span class=cb1&gt;value&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;virtual&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;Value2&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;get&lt;/span&gt; { &lt;span class=cb1&gt;return&lt;/span&gt; &lt;span class=cb2&gt;_value2&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;set&lt;/span&gt; { &lt;span class=cb2&gt;_value2&lt;/span&gt; = &lt;span class=cb1&gt;value&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;virtual&lt;/span&gt; &lt;span class=cb1&gt;decimal&lt;/span&gt; &lt;span class=cb2&gt;Result&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;get&lt;/span&gt; { &lt;span class=cb1&gt;return&lt;/span&gt; (&lt;span class=cb1&gt;decimal&lt;/span&gt;)(&lt;span class=cb5&gt;Math&lt;/span&gt;.&lt;span class=cb2&gt;Cos&lt;/span&gt;(&lt;span class=cb2&gt;Value1&lt;/span&gt;)*&lt;span class=cb5&gt;Math&lt;/span&gt;.&lt;span class=cb2&gt;Exp&lt;/span&gt;(&lt;span class=cb2&gt;Value2&lt;/span&gt;))
; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;set&lt;/span&gt; {
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;
&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;
&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;The property Result is generated
using the properties Value1 &lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/span&gt;and Value2.
In order for NHibernate to be able to map the Result property, a setter is needed,
but as you can see, it does nothing.&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;An item is stored in the following
table:&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;CREATE TABLE Items&lt;br&gt;
&lt;/span&gt;&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;(&lt;br&gt;
&lt;/span&gt;&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;&lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;id
int IDENTITY (1, 1) NOT NULL CONSTRAINT PK_Item PRIMARY KEY,&lt;br&gt;
&lt;/span&gt;&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; value1
int NOT NULL,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;value2
int NOT NULL,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;result
decimal(10, 2) NOT NULL&lt;br&gt;
)&lt;/span&gt;&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;
&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;Optimizing the application I found
out that everytime an Item was loaded, the item was also updated, even if the application
didn’t change any of the item values. After thinking a bit, I found out the problem. 
&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;Imagine an Item with the Value1
= 1 and Value2 = 3.&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;When NHibernate loads the Item,
it saves a copy of the original values for the Item, so the saved values are (Value1=1,
Value2=3 and Result=10.85). When the session is flushed, NHibernate compares the old
values with the current values, and if there is any difference, the object is marked
as dirty, and then an update is sent to the database.&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;As the Result property is calculated,
the value returned by the get method is always 10.852261914198, so NHibernate always
marks the item as dirty.&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;An option to fix this is to round
the Result to 2 decimal digits but that has the unwanted side effect to affect the
precision of all operations that use the Result property.&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;A better option is to implement
a custom interceptor that does this rounding for some specific properties. A NHibernate
interceptor is a class that gets called when in some important instants in the ORM
life cycle. In this particular scenario, the method I was interested in is the FindDirty
method, that is called to find out if the current entity is dirty or not, and among
the parameters passed to this method are the currentState and the previousState of
the object.&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;What I did was to round there the
current state of the generated properties. I needed a way to know which properties
to round, so I created two custom attributes, GeneratedProperties and GeneratedProperty.
In order for my interceptor to round a property, the class needs to have the GeneratedProperties
attribute set, if not, it is not further processed. &lt;span style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/span&gt;When
an instance implemented the GeneratedProperties attribute is found, its properties
are inspected and all of them that have the GeneratedProperty attribute set are automatically
rounded. The number of decimal digits to leave is specified in one of the attributes.
It is mandatory for the GeneratedProperties attribute and optional in the GeneratedProperty
attribute. If it is not specified in the GeneratedProperty attribute, the value specified
in the GeneratedProperties attribute is used. So if you have a lot of properties stored
in a similar way, you don’t have to specify the number of digits in several places.&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;The final Item class is:&lt;/span&gt;
&lt;/p&gt;
&lt;div class=cf&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;System&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;System&lt;/span&gt;.&lt;span class=cb2&gt;Collections&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;System&lt;/span&gt;.&lt;span class=cb2&gt;Collections&lt;/span&gt;.&lt;span class=cb2&gt;Generic&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;System&lt;/span&gt;.&lt;span class=cb2&gt;Text&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;NHibernateUtil&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;NHibernate&lt;/span&gt;.&lt;span class=cb2&gt;Classic&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;namespace&lt;/span&gt; &lt;span class=cb2&gt;Smaple&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
{
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span class=cb5&gt;GeneratedProperties&lt;/span&gt;(&lt;span class=cb6&gt;2&lt;/span&gt;)]
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;class&lt;/span&gt; &lt;span class=cb5&gt;Item&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;private&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;_id&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;private&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;_value1&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;private&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;_value2&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;private&lt;/span&gt; &lt;span class=cb1&gt;decimal&lt;/span&gt; &lt;span class=cb2&gt;_result&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;virtual&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;Id&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;get&lt;/span&gt; { &lt;span class=cb1&gt;return&lt;/span&gt; &lt;span class=cb2&gt;_id&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;set&lt;/span&gt; { &lt;span class=cb2&gt;_id&lt;/span&gt; = &lt;span class=cb1&gt;value&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;virtual&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;Value1&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;get&lt;/span&gt; { &lt;span class=cb1&gt;return&lt;/span&gt; &lt;span class=cb2&gt;_value1&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;set&lt;/span&gt; { &lt;span class=cb2&gt;_value1&lt;/span&gt; = &lt;span class=cb1&gt;value&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;virtual&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;Value2&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;get&lt;/span&gt; { &lt;span class=cb1&gt;return&lt;/span&gt; &lt;span class=cb2&gt;_value2&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;set&lt;/span&gt; { &lt;span class=cb2&gt;_value2&lt;/span&gt; = &lt;span class=cb1&gt;value&lt;/span&gt;;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span class=cb5&gt;GeneratedProperty&lt;/span&gt;]
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;virtual&lt;/span&gt; &lt;span class=cb1&gt;decimal&lt;/span&gt; &lt;span class=cb2&gt;Result&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;get&lt;/span&gt; { &lt;span class=cb1&gt;return&lt;/span&gt; (&lt;span class=cb1&gt;decimal&lt;/span&gt;)(&lt;span class=cb5&gt;Math&lt;/span&gt;.&lt;span class=cb2&gt;Cos&lt;/span&gt;(&lt;span class=cb2&gt;Value1&lt;/span&gt;)*&lt;span class=cb5&gt;Math&lt;/span&gt;.&lt;span class=cb2&gt;Exp&lt;/span&gt;(&lt;span class=cb2&gt;Value2&lt;/span&gt;))
; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;set&lt;/span&gt; {
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;Here is the code for the interceptor:&lt;/span&gt;
&lt;/p&gt;
&lt;div class=cf&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;System&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;System&lt;/span&gt;.&lt;span class=cb2&gt;Reflection&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;NHibernate&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;using&lt;/span&gt; &lt;span class=cb2&gt;NHibernate&lt;/span&gt;.&lt;span class=cb2&gt;Type&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb1&gt;namespace&lt;/span&gt; &lt;span class=cb2&gt;NHibernateUtil&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
{
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb3&gt;///&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span class=cb4&gt;Interceptor
that rounds generated values to avoid unnecessary updates to the DB.&lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;class&lt;/span&gt; &lt;span class=cb5&gt;GeneratedPropertiesInterceptor&lt;/span&gt; : &lt;span class=cb5&gt;EmptyInterceptor&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb3&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; #region&lt;/span&gt; Methods
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb3&gt;///&lt;/span&gt;&lt;span class=cb4&gt; &lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span class=cb4&gt;Finds
the dirty properties of an entity.&lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb3&gt;///&lt;/span&gt;&lt;span class=cb4&gt; &lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;param
name="entity"&amp;gt;&lt;/span&gt;&lt;span class=cb4&gt;The entity.&lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb3&gt;///&lt;/span&gt;&lt;span class=cb4&gt; &lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;param
name="id"&amp;gt;&lt;/span&gt;&lt;span class=cb4&gt;The identifier of the entity.&lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb3&gt;///&lt;/span&gt;&lt;span class=cb4&gt; &lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;param
name="currentState"&amp;gt;&lt;/span&gt;&lt;span class=cb4&gt;Current state of the entity.&lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb3&gt;///&lt;/span&gt;&lt;span class=cb4&gt; &lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;param
name="previousState"&amp;gt;&lt;/span&gt;&lt;span class=cb4&gt;Previous state of the entity.&lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb3&gt;///&lt;/span&gt;&lt;span class=cb4&gt; &lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;param
name="propertyNames"&amp;gt;&lt;/span&gt;&lt;span class=cb4&gt;The property names of the entity.&lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb3&gt;///&lt;/span&gt;&lt;span class=cb4&gt; &lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;param
name="types"&amp;gt;&lt;/span&gt;&lt;span class=cb4&gt;The types associated with the properties.&lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb3&gt;///&lt;/span&gt;&lt;span class=cb4&gt; &lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span class=cb4&gt;The
index of the changed properties or null to let NHibernate do the default check.&lt;/span&gt;&lt;span class=cb3&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;public&lt;/span&gt; &lt;span class=cb1&gt;override&lt;/span&gt; &lt;span class=cb1&gt;int&lt;/span&gt;[] &lt;span class=cb2&gt;FindDirty&lt;/span&gt;(&lt;span class=cb1&gt;object&lt;/span&gt; &lt;span class=cb2&gt;entity&lt;/span&gt;, &lt;span class=cb1&gt;object&lt;/span&gt; &lt;span class=cb2&gt;id&lt;/span&gt;, &lt;span class=cb1&gt;object&lt;/span&gt;[] &lt;span class=cb2&gt;currentState&lt;/span&gt;, &lt;span class=cb1&gt;object&lt;/span&gt;[] &lt;span class=cb2&gt;previousState&lt;/span&gt;, &lt;span class=cb1&gt;string&lt;/span&gt;[] &lt;span class=cb2&gt;propertyNames&lt;/span&gt;, &lt;span class=cb6&gt;IType&lt;/span&gt;[] &lt;span class=cb2&gt;types&lt;/span&gt;)
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb7&gt;// search
the generated property attribute for the entity&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb5&gt;Type&lt;/span&gt; &lt;span class=cb2&gt;entityType&lt;/span&gt; = &lt;span class=cb2&gt;entity&lt;/span&gt;.&lt;span class=cb2&gt;GetType&lt;/span&gt;();
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb5&gt;GeneratedPropertiesAttribute&lt;/span&gt; &lt;span class=cb2&gt;attr&lt;/span&gt; =
(&lt;span class=cb5&gt;GeneratedPropertiesAttribute&lt;/span&gt;)&lt;span class=cb5&gt;Attribute&lt;/span&gt;.&lt;span class=cb2&gt;GetCustomAttribute&lt;/span&gt;(&lt;span class=cb2&gt;entityType&lt;/span&gt;, &lt;span class=cb1&gt;typeof&lt;/span&gt;(&lt;span class=cb5&gt;GeneratedPropertiesAttribute&lt;/span&gt;), &lt;span class=cb1&gt;true&lt;/span&gt;);
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb7&gt;// if the
entity has generated properties&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;if&lt;/span&gt; (&lt;span class=cb2&gt;attr&lt;/span&gt; != &lt;span class=cb1&gt;null&lt;/span&gt;)
{
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb7&gt;//
iterate through the properties, modifying the generated ones&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;for&lt;/span&gt; (&lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;i&lt;/span&gt; = &lt;span class=cb8&gt;0&lt;/span&gt;; &lt;span class=cb2&gt;i&lt;/span&gt; &amp;lt; &lt;span class=cb2&gt;propertyNames&lt;/span&gt;.&lt;span class=cb2&gt;Length&lt;/span&gt;; &lt;span class=cb2&gt;i&lt;/span&gt;++)
{
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;string&lt;/span&gt; &lt;span class=cb2&gt;propertyName&lt;/span&gt; = &lt;span class=cb2&gt;propertyNames&lt;/span&gt;[&lt;span class=cb2&gt;i&lt;/span&gt;];
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb5&gt;PropertyInfo&lt;/span&gt; &lt;span class=cb2&gt;property&lt;/span&gt; = &lt;span class=cb2&gt;entityType&lt;/span&gt;.&lt;span class=cb2&gt;GetProperty&lt;/span&gt;(&lt;span class=cb2&gt;propertyName&lt;/span&gt;, &lt;span class=cb6&gt;BindingFlags&lt;/span&gt;.&lt;span class=cb2&gt;Public&lt;/span&gt; | &lt;span class=cb6&gt;BindingFlags&lt;/span&gt;.&lt;span class=cb2&gt;Instance&lt;/span&gt;);
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb7&gt;//
if the property does not exists, try the next one&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;if&lt;/span&gt; (&lt;span class=cb2&gt;property&lt;/span&gt; == &lt;span class=cb1&gt;null&lt;/span&gt;)
{
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;continue&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb7&gt;//
try to get the GeneratedPropertyAttribute for this property&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb5&gt;GeneratedPropertyAttribute&lt;/span&gt; &lt;span class=cb2&gt;genAttr&lt;/span&gt; =
(&lt;span class=cb5&gt;GeneratedPropertyAttribute&lt;/span&gt;)&lt;span class=cb5&gt;Attribute&lt;/span&gt;.&lt;span class=cb2&gt;GetCustomAttribute&lt;/span&gt;(&lt;span class=cb2&gt;property&lt;/span&gt;, &lt;span class=cb1&gt;typeof&lt;/span&gt;(&lt;span class=cb5&gt;GeneratedPropertyAttribute&lt;/span&gt;), &lt;span class=cb1&gt;true&lt;/span&gt;);
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb7&gt;//
if the attribute is present and the type is a decimal, round it&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;if&lt;/span&gt; ((&lt;span class=cb2&gt;genAttr&lt;/span&gt; != &lt;span class=cb1&gt;null&lt;/span&gt;)
&amp;amp;&amp;amp; (&lt;span class=cb2&gt;types&lt;/span&gt;[&lt;span class=cb2&gt;i&lt;/span&gt;].&lt;span class=cb2&gt;GetType&lt;/span&gt;()
== &lt;span class=cb1&gt;typeof&lt;/span&gt;(&lt;span class=cb5&gt;DecimalType&lt;/span&gt;))) {
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;int&lt;/span&gt; &lt;span class=cb2&gt;numDecimals&lt;/span&gt; =
(&lt;span class=cb2&gt;genAttr&lt;/span&gt;.&lt;span class=cb2&gt;DecimalDigits&lt;/span&gt; != &lt;span class=cb8&gt;0&lt;/span&gt;)
? &lt;span class=cb2&gt;genAttr&lt;/span&gt;.&lt;span class=cb2&gt;DecimalDigits&lt;/span&gt; : &lt;span class=cb2&gt;attr&lt;/span&gt;.&lt;span class=cb2&gt;DecimalDigits&lt;/span&gt;;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb2&gt;currentState&lt;/span&gt;[&lt;span class=cb2&gt;i&lt;/span&gt;] = &lt;span class=cb5&gt;Math&lt;/span&gt;.&lt;span class=cb2&gt;Round&lt;/span&gt;((&lt;span class=cb1&gt;decimal&lt;/span&gt;)&lt;span class=cb2&gt;currentState&lt;/span&gt;[&lt;span class=cb2&gt;i&lt;/span&gt;], &lt;span class=cb2&gt;numDecimals&lt;/span&gt;);
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
}
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class=cb1&gt;return&lt;/span&gt; &lt;span class=cb1&gt;base&lt;/span&gt;.&lt;span class=cb2&gt;FindDirty&lt;/span&gt;(&lt;span class=cb2&gt;entity&lt;/span&gt;, &lt;span class=cb2&gt;id&lt;/span&gt;, &lt;span class=cb2&gt;currentState&lt;/span&gt;, &lt;span class=cb2&gt;previousState&lt;/span&gt;, &lt;span class=cb2&gt;propertyNames&lt;/span&gt;, &lt;span class=cb2&gt;types&lt;/span&gt;);
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p class=cl&gt;
&lt;span class=cb3&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion&lt;/span&gt;
&lt;/p&gt;
&lt;p class=cl&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p class=cl&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;In future posts I’ll rant on about
NHibernate, its limitations and some things I didn’t like about it.&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN: 0cm 0cm 10pt"&gt;
&lt;span lang=EN-US style="mso-ansi-language: EN-US"&gt;PS: I have changed the way I was
displaying code. Previously I was using embedded styles and now the styles are not
embedded any more. The reason for it is because the code doesn't look good with the
current theme as I have switched to a dark colors in VS.NET to code. Let me know if
this breaks the code display for your RSS reader.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;a href="http://www.manuelabadia.com/blog/content/binary/GeneratedPropertiesInterceptor.zip"&gt;GeneratedPropertiesInterceptor.zip
(2,13 KB)&lt;/a&gt;&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=b169ef19-7123-4ab9-8724-36583bc7c16f" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,b169ef19-7123-4ab9-8724-36583bc7c16f.aspx</comments>
      <category>NHibernate</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=ae3c5e36-a337-4e3e-a3c3-a8e29b801880</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,ae3c5e36-a337-4e3e-a3c3-a8e29b801880.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,ae3c5e36-a337-4e3e-a3c3-a8e29b801880.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=ae3c5e36-a337-4e3e-a3c3-a8e29b801880</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I have updated my Membership and Role provider that use NHibernate for data access.
The changes are minimal. Now I'm using NHibernate 1.2.0 GA and a minor fix. The
instructions and the code can be found <a href="http://www.manuelabadia.com/blog/PermaLink,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx">here</a></p>
        <p>
This will be my last post until I return from London. Excuse me if I'm unable to reply
to non critical emails in the next few days.
</p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=ae3c5e36-a337-4e3e-a3c3-a8e29b801880" />
      </body>
      <title>NHibernate Membership and Role provider updated</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,ae3c5e36-a337-4e3e-a3c3-a8e29b801880.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,ae3c5e36-a337-4e3e-a3c3-a8e29b801880.aspx</link>
      <pubDate>Thu, 21 Jun 2007 08:55:47 GMT</pubDate>
      <description>&lt;p&gt;
I have updated my Membership and Role provider that use NHibernate for data access.
The changes are minimal. Now I'm&amp;nbsp;using NHibernate 1.2.0 GA and a minor fix. The
instructions and the code can be found &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
This will be my last post until I return from London. Excuse me if I'm unable to reply
to non critical emails in the next few days.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=ae3c5e36-a337-4e3e-a3c3-a8e29b801880" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,ae3c5e36-a337-4e3e-a3c3-a8e29b801880.aspx</comments>
      <category>ASP.NET;NHibernate</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=3b6ccb3f-2f2a-4dcb-a414-605371a00618</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=3b6ccb3f-2f2a-4dcb-a414-605371a00618</wfw:commentRss>
      <slash:comments>26</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Usually, the built-in providers for ASP.NET do not integrate very well with existing
applications. The membership provider has a very complex structure that in most cases
is not needed at all. The following diagram shows most of the tables and relations
for the built-in ASP.NET providers:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/providers.png" border="0" />
        </p>
        <p>
 
</p>
        <p>
The membership related tables are selected in red and the role related tables are
selected in blue. The default membership and roles provider have support to store
data for multiple applications using the aspnet_Applications table. I think this table
was introduced because some portal frameworks like dotnetnuke needed the ability to
store membership and role data for multiple users in a single store because they support
multiple portals. If you don't need this scenario (and most applications do not need
it), this only complicate things.
</p>
        <p>
Also, the built-in providers use tables that are not part of your application tables,
and some of those tables have quite a few columns, and probably some are not needed
by your application.
</p>
        <p>
If you do not use SQL Server, you can not use the default providers, so that is a
big showstopper.
</p>
        <p>
To overcome all of this problems I have created a custom membership and role provider
that use NHibernate and can be easily integrated with existing or future applications
using your own tables.
</p>
        <p>
The reference book about providers is:
</p>
        <p>
          <strong>
            <em>Professional ASP.NET 2.0 Security, Membership, and Role Management.</em>
          </strong>
        </p>
        <iframe style="WIDTH: 120px; HEIGHT: 240px" marginwidth="0" marginheight="0" src="http://rcm.amazon.com/e/cm?t=manuelabadias-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=0764596985&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" frameborder="0" scrolling="no">
        </iframe>
        <p>
I suggest you to read it if you really want to get deep into providers as it is an
excellent book.
</p>
        <p>
The NHCustomMembershipProvider uses NHibernate to do all membership related database
operations so it should work on all databases supported by NHibernate. The membership
data will be stored and retrieved from a table configured in the provider section
in the web.config so you can map it to an existing table like users. The column names
for your user table can also be configured in the provider section. The cool thing
about the provider is that it adapts its behaviour to the number of columns supported
by your data store. For example, if you use the provider and map it to your users
table where you only have the membership data for userId, userName, password and email,
it will work without any problem. If your data store supports more advanced options
of the membership provider like account lockout, password question and answer, password
salt or last activity date, that advanced functionality will be automatically available,
but it is not required. 
</p>
        <p>
The provider knows what functionality to offer based on the number of columns that
are mapped to your data store. To support account lockout when the user do not supply
a valid password after some tries in a predefined period of time you need to map the
isLockedOutColumn, failedPasswordAttemptCountColumn and failedPasswordAttemptWindowStartColumn
to columns in your data store.
</p>
        <p>
The default configuration for the provider is to use integer identities or sequences
for the user identifier, but that can be changed using the userIdType and idGeneratorClass
properties in the provider configuration section.
</p>
        <p>
If you use the provider with an existing user table, probably you will create the
users manually without using the CreateUser method from the membership provider. The
provider exposes the methods CheckPasswordPolicy, ValidatePassword, EncodePassword
and GenerateSalt to allow manual creation of the user in case you need it, without
sacrifying password strength.
</p>
        <p>
To finish with the custom membership provider lets see an example. If you want to
use the membership provider with a table like this (that has columns for all supported
functionality):
</p>
        <div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">CREATE TABLE </span>[dbo].[Users](
</p>
          <p style="MARGIN: 0px">
 [userId] [int] <span style="COLOR: blue">IDENTITY</span>(1,1) <span style="COLOR: blue">NOT
NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [username] [nvarchar](50) <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [email] [nvarchar](100) <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [password] [nvarchar](256) <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [passwordSalt] [nvarchar](64) <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [passwordFormat] [int] <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [passwordQuestion] [nvarchar](512) <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [passwordAnswer] [nvarchar](512) <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [failedPasswordAttemptCount] [int] <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [failedPasswordAttemptWindowStart] [smalldatetime] <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [failedPasswordAnswerAttemptCount] [int] <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [failedPasswordAnswerAttemptWindowStart] [smalldatetime] <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [lastPasswordChangedDate] [smalldatetime] <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [creationDate] [smalldatetime] <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [lastActivityDate] [smalldatetime] <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [isApproved] [bit] <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [isLockedOut] [bit] <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [lastLockOutDate] [smalldatetime] <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [lastLoginDate] [smalldatetime] <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [name] [nvarchar](256) <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [surname] [nvarchar](256) <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [address] [nvarchar](256) <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [phone] [nvarchar](16) <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [postalCode] [nvarchar](50) <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
 [comments] [nvarchar](<span style="COLOR: blue">max</span>) <span style="COLOR: blue">NULL</span>,
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">CONSTRAINT </span>[PK_Users] <span style="COLOR: blue">PRIMARY
KEY CLUSTERED </span></p>
          <p style="MARGIN: 0px">
    (
</p>
          <p style="MARGIN: 0px">
    [userId] <span style="COLOR: blue">ASC</span></p>
          <p style="MARGIN: 0px">
    )
</p>
          <p style="MARGIN: 0px">
)
</p>
        </div>
        <p>
          <!--EndFragment-->
        </p>
        <p>
The configuration section for the membership provider will be something like this:
</p>
        <div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">&lt;</span>
            <span style="COLOR: #a31515">membership</span>
            <span style="COLOR: blue">
            </span>
            <span style="COLOR: red">defaultProvider</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">NHCustomMembershipProvider</span>"<span style="COLOR: blue">&gt;</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">  &lt;</span>
            <span style="COLOR: #a31515">providers</span>
            <span style="COLOR: blue">&gt;</span>
          </p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">    &lt;</span>
            <span style="COLOR: #a31515">add</span>
            <span style="COLOR: blue">
            </span>
            <span style="COLOR: red">name</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">NHCustomMembershipProvider</span>"<span style="COLOR: blue"></span><span style="COLOR: red">type</span><span style="COLOR: blue">=</span>"<span style="COLOR: blue">NHCustomProviders.NHCustomMembershipProvider,
NHCustomProviders</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">enablePasswordReset</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">true</span>"<span style="COLOR: blue"></span><span style="COLOR: red">enablePasswordRetrieval</span><span style="COLOR: blue">=</span>"<span style="COLOR: blue">true</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">minRequiredNonAlphanumericCharacters</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">1</span>"<span style="COLOR: blue"></span><span style="COLOR: red">minRequiredPasswordLength</span><span style="COLOR: blue">=</span>"<span style="COLOR: blue">6</span>"<span style="COLOR: blue"></span><span style="COLOR: red">passwordFormat</span><span style="COLOR: blue">=</span>"<span style="COLOR: blue">Encrypted</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">maxInvalidPasswordAttempts</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">5</span>"<span style="COLOR: blue"></span><span style="COLOR: red">passwordAttemptWindow</span><span style="COLOR: blue">=</span>"<span style="COLOR: blue">5</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">requiresQuestionAndAnswer</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">true</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">requiresUniqueEmail</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">false</span>"
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">tableName</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">USERS</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">userIdColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">USERID</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">userIdType</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">Int32</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">idGeneratorClass</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">native</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">userNameColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">USERNAME</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">emailColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">EMAIL</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">passwordColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">PASSWORD</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">passwordSaltColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">PASSWORDSALT</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">passwordFormatColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">PASSWORDFORMAT</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">passwordQuestionColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">PASSWORDQUESTION</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">passwordAnswerColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">PASSWORDANSWER</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">failedPasswordAttemptCountColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">FAILEDPASSWORDATTEMPTCOUNT</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">failedPasswordAttemptWindowStartColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">FAILEDPASSWORDATTEMPTWINDOWSTART</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">failedPasswordAnswerAttemptCountColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">FAILEDPASSWORDANSWERATTEMPTCOUNT</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">failedPasswordAnswerAttemptWindowStartColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">FAILEDPASSWORDANSWERATTEMPTWINDOWSTART</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">lastPasswordChangedDateColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">LASTPASSWORDCHANGEDDATE</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">creationDateColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">CREATIONDATE</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">lastActivityDateColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">LASTACTIVITYDATE</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">isApprovedColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">ISAPPROVED</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">isLockedOutColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">ISLOCKEDOUT</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">lastLockOutDateColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">LASTLOCKOUTDATE</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">lastLoginDateColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">LASTLOGINDATE</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">commentsColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">COMMENTS</span>"
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">userNameColumnSize</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">50</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">emailColumnSize</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">50</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">passwordColumnSize</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">256</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">passwordSaltColumnSize</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">64</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">passwordQuestionColumnSize</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">512</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">passwordAnswerColumnSize</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">512</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">passwordSaltSize</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">16</span>"
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">raiseSystemEvents</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">true</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">dynamicUpdate</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">true</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">    /&gt;</span>
          </p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">  &lt;/</span>
            <span style="COLOR: #a31515">providers</span>
            <span style="COLOR: blue">&gt;</span>
          </p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">&lt;/</span>
            <span style="COLOR: #a31515">membership</span>
            <span style="COLOR: blue">&gt;</span>
          </p>
        </div>
        <p>
          <!--EndFragment-->
          <br />
    
<br />
The column sizes are optional but it is a good practice to fill them.
</p>
        <p>
The built-in provider raises events after a succesfully or a failed login. However,
ASP.NET 2.0 does not allow to create or raise built-in health monitoring events, so
I had to use reflection in a private method in order to raise the same events. That
means that the provider will not run in medium trust if it is not installed in the
GAC if you want to raise the system events. As this can be a showstopper to some people
I have added an option to disable system events generation (raiseSystemEvents).
</p>
        <p>
The provider reads the config section and programatically generates a mapping for
the specified columns in the ConfigureNHibernate method. The provider expects that
you have configured NHibernate in the web.config to work. If you need extra configuration
for the provider you can inherit from the provider and use override the ConfigureNHibernate
method, modifying the Configuration object that the base class returns.
</p>
        <p>
The NHCustomRoleProvider is also configurable in order adapt to your own tables. It
only needs a Users table with id and user name columns, a roles table with id and
role name columns, and a join table used to store the information for the many-to-many
relationship between the users and roles.
</p>
        <p>
For example, if we the previous user table with the following tables (FKs omitted
for brevity):
</p>
        <div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">CREATE TABLE </span>[dbo].[Roles](
</p>
          <p style="MARGIN: 0px">
    [roleId] [int] <span style="COLOR: blue">IDENTITY</span>(1,1) <span style="COLOR: blue">NOT
NULL</span>,
</p>
          <p style="MARGIN: 0px">
    [name] [nvarchar](50) <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">CONSTRAINT </span>[PK_Roles] <span style="COLOR: blue">PRIMARY
KEY CLUSTERED </span></p>
          <p style="MARGIN: 0px">
    (
</p>
          <p style="MARGIN: 0px">
       [roleId] <span style="COLOR: blue">ASC</span></p>
          <p style="MARGIN: 0px">
    )
</p>
          <p style="MARGIN: 0px">
)
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">CREATE TABLE </span>[dbo].[Users_In_Roles](
</p>
          <p style="MARGIN: 0px">
    [userId] [int] <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
    [roleId] [int] <span style="COLOR: blue">NOT NULL</span>,
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">CONSTRAINT </span>[PK_UsersInRoles] <span style="COLOR: blue">PRIMARY
KEY CLUSTERED </span></p>
          <p style="MARGIN: 0px">
    (
</p>
          <p style="MARGIN: 0px">
       [userId] <span style="COLOR: blue">ASC</span>,
</p>
          <p style="MARGIN: 0px">
       [roleId] <span style="COLOR: blue">ASC</span></p>
          <p style="MARGIN: 0px">
    )
</p>
          <p style="MARGIN: 0px">
)
</p>
        </div>
        <!--EndFragment-->
        <p>
 
</p>
        <p>
The configuration section for the role provider will be something like this:
</p>
        <div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">&lt;</span>
            <span style="COLOR: #a31515">roleManager</span>
            <span style="COLOR: blue">
            </span>
            <span style="COLOR: red">defaultProvider</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">NHCustomRoleProvider</span>"<span style="COLOR: blue"></span><span style="COLOR: red">enabled</span><span style="COLOR: blue">=</span>"<span style="COLOR: blue">true</span>"<span style="COLOR: blue">&gt;</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">  &lt;</span>
            <span style="COLOR: #a31515">providers</span>
            <span style="COLOR: blue">&gt;</span>
          </p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">    &lt;</span>
            <span style="COLOR: #a31515">add</span>
            <span style="COLOR: blue">
            </span>
            <span style="COLOR: red">name</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">NHCustomRoleProvider</span>"<span style="COLOR: blue"></span><span style="COLOR: red">type</span><span style="COLOR: blue">=</span>"<span style="COLOR: blue">NHCustomProviders.NHCustomRoleProvider,
NHCustomProviders</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">userTableName</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">USERS</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">userIdColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">USERID</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">userIdType</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">Int32</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">userIdGeneratorClass</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">native</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">userNameColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">USERNAME</span>"
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">roleTableName</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">ROLES</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">roleIdColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">ROLEID</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">roleIdType</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">Int32</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">roleIdGeneratorClass</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">native</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">roleNameColumn</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">NAME</span>"
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">joinTableName</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">USERS_IN_ROLES</span>"
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">userNameColumnSize</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">50</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">        </span>
            <span style="COLOR: red">roleNameColumnSize</span>
            <span style="COLOR: blue">=</span>"<span style="COLOR: blue">50</span>"
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">    /&gt;</span>
          </p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">  &lt;/</span>
            <span style="COLOR: #a31515">providers</span>
            <span style="COLOR: blue">&gt;</span>
          </p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">&lt;/</span>
            <span style="COLOR: #a31515">roleManager</span>
            <span style="COLOR: blue">&gt;</span>
          </p>
        </div>
        <p>
          <!--EndFragment-->
        </p>
        <p>
          <br />
Note that the id columns in the join table need be named as in their respective tables
in order to work.<br />
    
<br />
Programatically creating the mapping using the CreateMappings for something more complex
than a single table seems to be something very tied to the NHibernate implementation
so I opted to create a XmlDocument with the mapping read from the configuration settings
as it seems to be the best thing to do in complex cases.
</p>
        <p>
One of the problems I faced with the NHCustomRoleProvider is that some times I wanted
to save or delete data from one side of the many-to-many relationship but in some
cases I wanted to use the other side. If you know a bit of NHibernate you know that
the inverse attribute controls what side of the relationship has to be used in order
to have changes persisted. As I was generating the mapping dynamically I created two
session factories, one with the inverse set to true on one side and the other with
the inverse in the other side. That way I open a connection in the session factory
that has the mapping with the inverse in the side of the relationship I want.
</p>
        <p>
I'd appreciate usage feedback, suggestions, bug reports, etc. I have only tried these
providers with NHibernate 1.2.0 GA and the MsSql2005Dialect so let me know if
it works in other configurations.
</p>
        <p>
Please do not store the providers in your server. Link to this page instead. Updates
to the providers will be posted in this page. 
</p>
        <p>
          <font size="4">
            <strong>
              <em>History</em>
            </strong>
          </font>
        </p>
        <p>
          <strong>v1.0 - 08/04/2007</strong>
        </p>
        <p>
          <strong>v1.1 - 21/06/2007</strong>
        </p>
        <ul dir="ltr" style="MARGIN-RIGHT: 0px">
          <li>
Now using NHibernate 1.2.0 GA 
</li>
          <li>
Some minor fixes</li>
        </ul>
        <p>
          <strong>v1.2 - 12/10/2007:</strong>
        </p>
        <ul>
          <li>
Fixed an important bug that didn’t prevent locked out users from login in. 
</li>
          <li>
Added a CreateUserWizardEx control that allows creating a user with extra information
in an easy way. 
</li>
          <li>
Added auto unlock support. 
</li>
          <li>
Fixed some minor bugs/typos.</li>
        </ul>
        <p>
For more details about the features introduced in version 1.2 take a look <a href="http://www.manuelabadia.com/blog/PermaLink,guid,27e22b2c-af95-4f4c-befd-1debc5841735.aspx">here</a>.
</p>
        <p>
          <strong>v2.0 - 01/08/2008:</strong>
        </p>
        <p>
For more details about the features introduced in version 2.0 and a sample of its
usage take a look <a href="http://www.manuelabadia.com/blog/PermaLink,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx">here</a>.
</p>
        <p>
          <a href="http://www.manuelabadia.com/blog/content/binary/NHCustomProviders_bin.zip">NHCustomProviders_bin.zip
(67 KB)</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/content/binary/NHCustomProviders_source.zip">NHCustomProviders_source.zip
(122 KB)</a>
        </p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=3b6ccb3f-2f2a-4dcb-a414-605371a00618" />
      </body>
      <title>Custom Membership and Role Providers using NHibernate</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx</link>
      <pubDate>Sun, 08 Apr 2007 16:21:02 GMT</pubDate>
      <description>&lt;p&gt;
Usually, the built-in providers for ASP.NET do not integrate very well with existing
applications. The membership provider has a very complex structure that in most cases
is not needed at all. The following diagram shows most of the tables and relations
for the built-in ASP.NET providers:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/providers.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
The membership related tables are selected in red and the role related tables are
selected in blue. The default membership and roles provider have support to store
data for multiple applications using the aspnet_Applications table. I think this table
was introduced because some portal frameworks like dotnetnuke needed the ability to
store membership and role data for multiple users in a single store because they support
multiple portals. If you don't need this scenario (and most applications do not need
it), this only complicate things.
&lt;/p&gt;
&lt;p&gt;
Also, the built-in providers use tables that are not part of your application tables,
and some of those tables have quite a few columns, and probably some are not needed
by your application.
&lt;/p&gt;
&lt;p&gt;
If you do not use SQL Server, you can not use the default providers, so that is a
big showstopper.
&lt;/p&gt;
&lt;p&gt;
To overcome all of this problems I have created a custom membership and role provider
that use NHibernate and can be easily integrated with existing or future applications
using your own tables.
&lt;/p&gt;
&lt;p&gt;
The reference book about providers is:
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;&lt;em&gt;Professional ASP.NET 2.0 Security, Membership, and Role Management.&lt;/em&gt;&lt;/strong&gt;
&lt;/p&gt;
&lt;iframe style="WIDTH: 120px; HEIGHT: 240px" marginwidth=0 marginheight=0 src="http://rcm.amazon.com/e/cm?t=manuelabadias-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=0764596985&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" frameborder=0 scrolling=no&gt;
&lt;/iframe&gt;
&lt;p&gt;
I suggest you to read it if you really want to get deep into providers as it is an
excellent book.
&lt;/p&gt;
&lt;p&gt;
The NHCustomMembershipProvider uses NHibernate to do all membership related database
operations so it should work on all databases supported by NHibernate. The membership
data will be stored and retrieved from a table configured in the provider section
in the web.config so you can map it to an existing table like users. The column names
for your user table can also be configured in the provider section. The cool thing
about the provider is that it adapts its behaviour to the number of columns supported
by your data store. For example, if you use the provider and map it to your users
table where you only have the membership data for userId, userName, password and email,
it will work without any problem. If your data store supports more advanced options
of the membership provider like account lockout, password question and answer, password
salt or last activity date, that advanced functionality will be automatically available,
but it is not required. 
&lt;/p&gt;
&lt;p&gt;
The provider knows what functionality to offer based on the number of columns that
are mapped to your data store. To support account lockout when the user do not supply
a valid password after some tries in a predefined period of time you need to map the
isLockedOutColumn, failedPasswordAttemptCountColumn and failedPasswordAttemptWindowStartColumn
to columns in your data store.
&lt;/p&gt;
&lt;p&gt;
The default configuration for the provider is to use integer identities or sequences
for the user identifier, but that can be changed using the userIdType and idGeneratorClass
properties in the provider configuration section.
&lt;/p&gt;
&lt;p&gt;
If you use the provider with an existing user table, probably you will create the
users manually without using the CreateUser method from the membership provider. The
provider exposes the methods CheckPasswordPolicy, ValidatePassword, EncodePassword
and GenerateSalt to allow manual creation of the user in case you need it, without
sacrifying password strength.
&lt;/p&gt;
&lt;p&gt;
To finish with the custom membership provider lets see an example. If you want to
use the membership provider with a table like this (that has columns for all supported
functionality):
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New"&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;CREATE TABLE &lt;/span&gt;[dbo].[Users](
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[userId] [int] &lt;span style="COLOR: blue"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span style="COLOR: blue"&gt;NOT
NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[username] [nvarchar](50) &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[email] [nvarchar](100) &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[password] [nvarchar](256) &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[passwordSalt] [nvarchar](64) &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[passwordFormat] [int] &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[passwordQuestion] [nvarchar](512) &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[passwordAnswer] [nvarchar](512) &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[failedPasswordAttemptCount] [int] &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[failedPasswordAttemptWindowStart] [smalldatetime] &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[failedPasswordAnswerAttemptCount] [int] &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[failedPasswordAnswerAttemptWindowStart] [smalldatetime] &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[lastPasswordChangedDate] [smalldatetime] &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[creationDate] [smalldatetime] &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[lastActivityDate] [smalldatetime] &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[isApproved] [bit] &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[isLockedOut] [bit] &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[lastLockOutDate] [smalldatetime] &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[lastLoginDate] [smalldatetime] &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[name] [nvarchar](256) &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[surname] [nvarchar](256) &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[address] [nvarchar](256) &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[phone] [nvarchar](16) &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[postalCode] [nvarchar](50) &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;[comments] [nvarchar](&lt;span style="COLOR: blue"&gt;max&lt;/span&gt;) &lt;span style="COLOR: blue"&gt;NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;CONSTRAINT &lt;/span&gt;[PK_Users] &lt;span style="COLOR: blue"&gt;PRIMARY
KEY CLUSTERED &lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; (
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; [userId] &lt;span style="COLOR: blue"&gt;ASC&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; )
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
)
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;!--EndFragment--&gt;
&lt;/p&gt;
&lt;p&gt;
The configuration section for the membership provider will be something like this:
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New"&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;membership&lt;/span&gt;&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;defaultProvider&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;NHCustomMembershipProvider&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;providers&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;add&lt;/span&gt;&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;name&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;NHCustomMembershipProvider&lt;/span&gt;"&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;type&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;NHCustomProviders.NHCustomMembershipProvider,
NHCustomProviders&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;enablePasswordReset&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;true&lt;/span&gt;"&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;enablePasswordRetrieval&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;true&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;minRequiredNonAlphanumericCharacters&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;1&lt;/span&gt;"&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;minRequiredPasswordLength&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;6&lt;/span&gt;"&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordFormat&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;Encrypted&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;maxInvalidPasswordAttempts&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;5&lt;/span&gt;"&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordAttemptWindow&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;5&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;requiresQuestionAndAnswer&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;true&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;requiresUniqueEmail&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;false&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;tableName&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;USERS&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;userIdColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;USERID&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;userIdType&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;Int32&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;idGeneratorClass&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;native&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;userNameColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;USERNAME&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;emailColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;EMAIL&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;PASSWORD&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordSaltColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;PASSWORDSALT&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordFormatColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;PASSWORDFORMAT&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordQuestionColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;PASSWORDQUESTION&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordAnswerColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;PASSWORDANSWER&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;failedPasswordAttemptCountColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;FAILEDPASSWORDATTEMPTCOUNT&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;failedPasswordAttemptWindowStartColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;FAILEDPASSWORDATTEMPTWINDOWSTART&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;failedPasswordAnswerAttemptCountColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;FAILEDPASSWORDANSWERATTEMPTCOUNT&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;failedPasswordAnswerAttemptWindowStartColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;FAILEDPASSWORDANSWERATTEMPTWINDOWSTART&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;lastPasswordChangedDateColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;LASTPASSWORDCHANGEDDATE&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;creationDateColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;CREATIONDATE&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;lastActivityDateColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;LASTACTIVITYDATE&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;isApprovedColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;ISAPPROVED&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;isLockedOutColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;ISLOCKEDOUT&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;lastLockOutDateColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;LASTLOCKOUTDATE&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;lastLoginDateColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;LASTLOGINDATE&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;commentsColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;COMMENTS&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;userNameColumnSize&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;50&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;emailColumnSize&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;50&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordColumnSize&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;256&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordSaltColumnSize&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;64&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordQuestionColumnSize&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;512&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordAnswerColumnSize&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;512&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;passwordSaltSize&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;16&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;raiseSystemEvents&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;true&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;dynamicUpdate&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;true&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; /&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;providers&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;membership&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;!--EndFragment--&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
The column sizes are optional but it is a good practice to fill them.
&lt;/p&gt;
&lt;p&gt;
The built-in provider raises events after a succesfully or a failed login. However,
ASP.NET 2.0 does not allow to create or raise built-in health monitoring events, so
I had to use reflection in a private method in order to raise the same events. That
means that the provider will not run in medium trust if it is not installed in the
GAC if you want to raise the system events. As this can be a showstopper to some people
I have added an option to disable system events generation (raiseSystemEvents).
&lt;/p&gt;
&lt;p&gt;
The provider reads the config section and programatically generates a mapping for
the specified columns in the ConfigureNHibernate method. The provider expects that
you have configured NHibernate in the web.config to work. If you need extra configuration
for the provider you can inherit from the provider and use override the ConfigureNHibernate
method, modifying the Configuration object that the base class returns.
&lt;/p&gt;
&lt;p&gt;
The NHCustomRoleProvider is also configurable in order adapt to your own tables. It
only needs a Users table with id and user name columns, a roles table with id and
role name columns, and a join table used to store the information for the many-to-many
relationship between the users and roles.
&lt;/p&gt;
&lt;p&gt;
For example, if we the previous user table with the following tables (FKs omitted
for brevity):
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New"&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;CREATE TABLE &lt;/span&gt;[dbo].[Roles](
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; [roleId] [int] &lt;span style="COLOR: blue"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span style="COLOR: blue"&gt;NOT
NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; [name] [nvarchar](50) &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;CONSTRAINT &lt;/span&gt;[PK_Roles] &lt;span style="COLOR: blue"&gt;PRIMARY
KEY CLUSTERED &lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; (
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; [roleId] &lt;span style="COLOR: blue"&gt;ASC&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; )
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;CREATE TABLE &lt;/span&gt;[dbo].[Users_In_Roles](
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; [userId] [int] &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; [roleId] [int] &lt;span style="COLOR: blue"&gt;NOT NULL&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;CONSTRAINT &lt;/span&gt;[PK_UsersInRoles] &lt;span style="COLOR: blue"&gt;PRIMARY
KEY CLUSTERED &lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; (
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; [userId] &lt;span style="COLOR: blue"&gt;ASC&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; [roleId] &lt;span style="COLOR: blue"&gt;ASC&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; )
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
)
&lt;/p&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
The configuration section for the role provider will be something like this:
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New"&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;roleManager&lt;/span&gt;&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;defaultProvider&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;NHCustomRoleProvider&lt;/span&gt;"&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;enabled&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;true&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;providers&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;add&lt;/span&gt;&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;name&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;NHCustomRoleProvider&lt;/span&gt;"&lt;span style="COLOR: blue"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;type&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;NHCustomProviders.NHCustomRoleProvider,
NHCustomProviders&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;userTableName&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;USERS&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;userIdColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;USERID&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;userIdType&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;Int32&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;userIdGeneratorClass&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;native&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;userNameColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;USERNAME&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;roleTableName&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;ROLES&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;roleIdColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;ROLEID&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;roleIdType&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;Int32&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;roleIdGeneratorClass&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;native&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;roleNameColumn&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;NAME&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;joinTableName&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;USERS_IN_ROLES&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;userNameColumnSize&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;50&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: red"&gt;roleNameColumnSize&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;"&lt;span style="COLOR: blue"&gt;50&lt;/span&gt;"
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;nbsp; /&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;providers&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;roleManager&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;!--EndFragment--&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;br&gt;
Note that the id columns in the join table need be named as in their respective tables
in order to work.&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
Programatically creating the mapping using the CreateMappings for something more complex
than a single table seems to be something very tied to the NHibernate implementation
so I opted to create a XmlDocument with the mapping read from the configuration settings
as it seems to be the best thing to do in complex cases.
&lt;/p&gt;
&lt;p&gt;
One of the problems I faced with the NHCustomRoleProvider is that some times I wanted
to save or delete data from one side of the many-to-many relationship but in some
cases I wanted to use the other side. If you know a bit of NHibernate you know that
the inverse attribute controls what side of the relationship has to be used in order
to have changes persisted. As I was generating the mapping dynamically I created two
session factories, one with the inverse set to true on one side and the other with
the inverse in the other side. That way I open a connection in the session factory
that has the mapping with the inverse in the side of the relationship I want.
&lt;/p&gt;
&lt;p&gt;
I'd appreciate usage feedback, suggestions, bug reports, etc. I have only tried these
providers with NHibernate 1.2.0&amp;nbsp;GA and the MsSql2005Dialect so let me know if
it works in other configurations.
&lt;/p&gt;
&lt;p&gt;
Please do not store the providers in your server. Link to this page instead. Updates
to the providers will be posted in this page. 
&lt;/p&gt;
&lt;p&gt;
&lt;font size=4&gt;&lt;strong&gt;&lt;em&gt;History&lt;/em&gt;&lt;/strong&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;v1.0&amp;nbsp;-&amp;nbsp;08/04/2007&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;v1.1 - 21/06/2007&lt;/strong&gt;
&lt;/p&gt;
&lt;ul dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;li&gt;
Now using NHibernate 1.2.0 GA 
&lt;li&gt;
Some minor fixes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;strong&gt;v1.2&amp;nbsp;- 12/10/2007:&lt;/strong&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Fixed an important bug that didn’t prevent locked out users from login in. 
&lt;li&gt;
Added a CreateUserWizardEx control that allows creating a user with extra information
in an easy way. 
&lt;li&gt;
Added auto unlock support. 
&lt;li&gt;
Fixed some minor bugs/typos.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
For more details about the features introduced in version 1.2 take a look &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,27e22b2c-af95-4f4c-befd-1debc5841735.aspx"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;v2.0&amp;nbsp;- 01/08/2008:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
For more details about the features introduced in version 2.0 and a sample of its
usage&amp;nbsp;take a look &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/content/binary/NHCustomProviders_bin.zip"&gt;NHCustomProviders_bin.zip
(67 KB)&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/content/binary/NHCustomProviders_source.zip"&gt;NHCustomProviders_source.zip
(122 KB)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=3b6ccb3f-2f2a-4dcb-a414-605371a00618" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx</comments>
      <category>ASP.NET;Microsoft .NET Framework;NHibernate</category>
    </item>
  </channel>
</rss>