Re: Speed improvement using compile timegenerate proxies

"Jon Palmer" <[email protected]> Mon, 1 Sep 2008 12:33:53 -0400
Newsgroups gmane.comp.windows.dotnet.nhibernate.devel
Message-ID <8EE6E8CD12C62F4A99424FC34C543D75C7DC84@shrapnel.cn.contactnetworks.com>
This is a multi-part message in MIME format.

--===============1042934962==
Content-class: urn:content-classes:message
Content-Type: multipart/alternative;
	boundary="----_=_NextPart_001_01C90C50.22F350EF"

This is a multi-part message in MIME format.

------_=_NextPart_001_01C90C50.22F350EF
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

What kind of performance improvements are we talking about? Can you =
provide some hard numbers?

=20

From: [email protected] =
[mailto:[email protected]] On Behalf =
Of Fabio Maulo
Sent: Monday, September 01, 2008 5:27 AM
To: the NHibernate development list
Subject: Re: [NHibernate-development] Speed improvement using compile =
timegenerate proxies

=20

And please since NH have a proxyfactoryfactory and ByteCodeProvider try =
to create separate injectable implementation.
Then we can test it in the core and hopeful use the new implementation =
as default.

2008/9/1 "Andr=E9s G. Aragoneses" <[email protected]>

+1

I've had similar performance issues and I would vote for this to be
included in NH Core vNext, so let's start creating a JIRA issue for it,
right?

Johan, wonderful research! Do you have rough benchmark numbers about the
performance increase? A simple percentage number?

Regards,

       Andr=E9s



Johan Kirsten wrote:
> Greetings
>
> I recently had the opportunity to move a project onto NHibernate. The
> project was using Gentle.NET. After moving the project onto =
NHibernate,
> I noticed that the application had become slower. For those not =
familiar
> with Gentle.NET, one of the biggest differences between Gentle.NET and
> NHibernate is the use of runtime generated proxies. Gentle.NET does =
not
> make use of runtime generated proxies, but rather method calls.
>
> An example of an NHibernate objects would be:
>
> *   public class Invoice {
>       private int _id;
>       private string _reference;
>       private Company _company;
>       private IList<InvoiceItem> _invoiceItems;*
> **
> *      public Invoice() {
>       }*
> **
> *      public int Id {
>          get { return _id; }
>          set { _id =3D value; }
>       }*
> **
> *      public virtual string Reference {
>          get { return _reference; }
>          set { _reference =3D value; }
>       }*
> **
> *      public virtual Company Company {
>          get { return _company; }
>          set { _company =3D value; }
>       }*
> **
> *      public virtual IList<InvoiceItem> InvoiceItems {
>          get { return _invoiceItems; }
>          set { _invoiceItems =3D value; }
>       }
>    }*
> **
> *   public class Company {
>       private int _id;
>       private string _name;*
> **
> *      public Company() {
>       }*
> **
> *      public int Id {
>          get { return _id; }
>          set { _id =3D value; }
>       }*
> **
> *      public string Name {
>          get { return _name; }
>          set { _name =3D value; }
>       }
>    }*
>
> The equivalent for Gentle.NET would be:
>
> *   public class Invoice {
>       private int _id;
>       private string _reference;
>       private int _companyKey;*
> **
> *      public Invoice() {
>       }*
> **
> *      public int Id {
>          get { return _id; }
>          set { _id =3D value; }
>       }*
> **
> *      public virtual string Reference {
>          get { return _reference; }
>          set { _reference =3D value; }
>       }*
> **
> *      public int CompanyKey {
>          get { return _companyKey; }
>          set { _companyKey =3D value; }
>       }*
> **
> *      public Company GetCompany() {
>          // Code that executes SQL and return company for current =
invoice
>       }*
> **
> *      public static IList<Invoice> GetList() {
>          // Code that executes SQL and returns all invoices
>       }
>    }*
> **
> *   public class Company {
>       private int _id;
>       private string _name;*
> **
> *      public Company() {
>       }*
> **
> *      public int Id {
>          get { return _id; }
>          set { _id =3D value; }
>       }*
> **
> *      public string Name {
>          get { return _name; }
>          set { _name =3D value; }
>       }*
> **
> *      public IList<Invoice> GetInvoiceList() {
>          // Code that executes SQL and returns invoices for current =
company
>       }*
> **
> *      public static IList<Company> GetList() {
>          // Code that executes SQL and returns all companies
>       }
>    }*
>
> It is important to note that - in general and assuming lazy loading -
> Gentle.NET and NHibernate will execute the same SQL at the same point =
in
> code. For example the Gentle.NET code:
>
> *   IList invoiceList =3D Invoice.GetList();
>    foreach (Invoice invoice in invoiceList) {
>       Company company =3D invoice.GetCompany();*
> **
> *      // Print invoice and company information
>    }*
>
> will request a list of invoices and the company for each invoice.
> NHibernate will do the same:
>
> *   IList invoiceList =3D InvoiceDAO.GetList();
>    foreach (Invoice invoice in invoiceList) {
>       Company company =3D invoice.Company;*
> **
> *      // Print invoice and company information
>    }*
>
> What I found was that the Gentle.NET code was faster. The only
> difference was the runtime generated proxies.
>
> The point I am trying to make is NHibernate takes a performance hit
> because of runtime generated proxies. I investigated and realised that
> the queries that were taking the longest were those retrieving lists =
of
> complex objects (objects containing other objects). These were the
> objects that used the most runtime generated proxies. I dived into the
> NHibernate code to understand why this is happening. What I discovered
> is that if you query a List of Invoices, NHibernate will compile a =
proxy
> for each Company of each row.
>
> To make it clear, for the first row in an Invoice results set,
> NHibernate (using Castle's dynamic proxy) generates a Company proxy =
type
> and then instantiates the proxy. For the second row, NHibernate again
> generates a Company proxy type and then instantiates the proxy.
> Therefore for a 100 invoices the same Company proxy type will be
> generated 100 times. After investigation I confirmed that this holds
> true for NH 1.2.1 and 2.0, although I suspect that NH 2.0 does not
> suffer as much due to optimization in Castle's new dynamic proxy.
>
> To confirm my suspisions I experimented with NH 1.2.1. I altered the
> code of NHibernate.Proxy.CastleProxyFactory, which is responsible for
> proxy generation. I had it store the type on its first pass and then =
to
> use the stored type to instantiate each instance. I added the data =
member:
>
> *   private System.Type _proxyType;*
>
> And altered the GetProxy method from:
>
> *   public INHibernateProxy GetProxy(object id, ISessionImplementor
> session) {
>       try {
>          CastleLazyInitializer initializer =3D new
> CastleLazyInitializer(_persistentClass, id, _getIdentifierMethod,
> _setIdentifierMethod, session);*
> **
> *         object generatedProxy =3D null;*
> **
> *         if (IsClassProxy) {
>             generatedProxy =3D
> _proxyGenerator.CreateClassProxy(_persistentClass, _interfaces,
> initializer, false);
>          }
>          else {
>             generatedProxy =3D =
_proxyGenerator.CreateProxy(_interfaces,
> initializer, new object());
>          }*
> **
> *         initializer._constructed =3D true;
>          return (INHibernateProxy)generatedProxy;
>       }
>       catch (Exception e) {
>          log.Error("Creating a proxy instance failed", e);
>          throw new HibernateException("Creating a proxy instance
> failed", e);
>       }
>    }*
>
> to:
>
> *   public INHibernateProxy GetProxy(object id, ISessionImplementor
> session) {
>       try {
>          CastleLazyInitializer initializer =3D new
> CastleLazyInitializer(_persistentClass, id, _getIdentifierMethod,
> _setIdentifierMethod, session);*
> **
> *         object generatedProxy =3D null;*
> **
> *         if (IsClassProxy) {
>             if (_proxyType =3D=3D null)
>                _proxyType =3D
> _proxyGenerator.ProxyBuilder.CreateClassProxy(_persistentClass,
> _interfaces);*
> **
> *            generatedProxy =3D Activator.CreateInstance(_proxyType,
> initializer);
>          }
>          else {
>             if (_proxyType =3D=3D null)
>                _proxyType =3D
> _proxyGenerator.ProxyBuilder.CreateInterfaceProxy(_interfaces,
> typeof(object));*
> **
> *            generatedProxy =3D Activator.CreateInstance(_proxyType, =
new
> object[] { initializer, new object() });
>          }*
> **
> *         initializer._constructed =3D true;
>          return (INHibernateProxy)generatedProxy;
>       }
>       catch (Exception e) {
>          log.Error("Creating a proxy instance failed", e);
>          throw new HibernateException("Creating a proxy instance
> failed", e);
>       }
>    }*
>
> This provided a speed improvement, but this isn't a solution. I do not
> want any delays at runtime due to proxy generation. I wanted to
> translate all of the types at startup. But for a lot of classes this
> would take too long and use too much memory. Then I found compile time
> generated proxies and it fit perfectly. Check out
> http://code.google.com/p/nhibernateproxygenerator/ by WC Pierce. I
> downloaded the source code and altered it to compile multiple =
libraries
> (my domain is spread over multiple libraries). The library it =
generated
> contains a ProxyFactoryFactory which you can use by setting the
> "proxyfactory.factory_class" property in your config file:
>
> *      <property
> name=3D"proxyfactory.factory_class">StaticProxyFactoryFactory,
> Library.Proxies</property>*
>
> It worked amazingly well. The speed improved significantly. It does =
take
> a while to compile the proxies. Especially if you have a lot of =
classes.
> So I only plan to do this on deployment. I will continue to use =
runtime
> generated proxies in my debug environment. This solution seems to work
> very well. Please provide any thoughts and comments. I am especially
> interested in hearing any comments from people that can point out any
> serious downside to this approach. Are there specific reasons why
> runtime generated proxies are prefered over compile time generated
> proxies that I am not aware of?
>
> Finally I want to state that I hope that the NHibernate community will
> contemplate making compile time proxy generation a standard feature in
> the next release of NHibernate.
>
> Thanks
>
> Johan Kirsten
>
>

> =
------------------------------------------------------------------------

>
> =
-------------------------------------------------------------------------=

> This SF.Net email is sponsored by the Moblin Your Move Developer's =
challenge
> Build the coolest Linux based applications with Moblin SDK & win great =
prizes
> Grand prize is a trip for two to an Open Source event anywhere in the =
world
> http://moblin-contest.org/redirect.php?banner_id=3D100&url=3D/
>
>
> =
------------------------------------------------------------------------
>
> _______________________________________________
> Nhibernate-development mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/nhibernate-development


-------------------------------------------------------------------------=

This SF.Net email is sponsored by the Moblin Your Move Developer's =
challenge
Build the coolest Linux based applications with Moblin SDK & win great =
prizes
Grand prize is a trip for two to an Open Source event anywhere in the =
world
http://moblin-contest.org/redirect.php?banner_id=3D100&url=3D/
_______________________________________________
Nhibernate-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/nhibernate-development




--=20
Fabio Maulo


------_=_NextPart_001_01C90C50.22F350EF
Content-Type: text/html;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
charset=3Diso-8859-1">
<html xmlns:v=3D"urn:schemas-microsoft-com:vml" =
xmlns:o=3D"urn:schemas-microsoft-com:office:office" =
xmlns:w=3D"urn:schemas-microsoft-com:office:word" =
xmlns:x=3D"urn:schemas-microsoft-com:office:excel" =
xmlns:p=3D"urn:schemas-microsoft-com:office:powerpoint" =
xmlns:a=3D"urn:schemas-microsoft-com:office:access" =
xmlns:dt=3D"uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" =
xmlns:s=3D"uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" =
xmlns:rs=3D"urn:schemas-microsoft-com:rowset" xmlns:z=3D"#RowsetSchema" =
xmlns:b=3D"urn:schemas-microsoft-com:office:publisher" =
xmlns:ss=3D"urn:schemas-microsoft-com:office:spreadsheet" =
xmlns:c=3D"urn:schemas-microsoft-com:office:component:spreadsheet" =
xmlns:odc=3D"urn:schemas-microsoft-com:office:odc" =
xmlns:oa=3D"urn:schemas-microsoft-com:office:activation" =
xmlns:html=3D"http://www.w3.org/TR/REC-html40" =
xmlns:q=3D"http://schemas.xmlsoap.org/soap/envelope/" xmlns:D=3D"DAV:" =
xmlns:x2=3D"http://schemas.microsoft.com/office/excel/2003/xml" =
xmlns:ois=3D"http://schemas.microsoft.com/sharepoint/soap/ois/" =
xmlns:dir=3D"http://schemas.microsoft.com/sharepoint/soap/directory/" =
xmlns:ds=3D"http://www.w3.org/2000/09/xmldsig#" =
xmlns:dsp=3D"http://schemas.microsoft.com/sharepoint/dsp" =
xmlns:udc=3D"http://schemas.microsoft.com/data/udc" =
xmlns:xsd=3D"http://www.w3.org/2001/XMLSchema" =
xmlns:sub=3D"http://schemas.microsoft.com/sharepoint/soap/2002/1/alerts/"=
 xmlns:ec=3D"http://www.w3.org/2001/04/xmlenc#" =
xmlns:sp=3D"http://schemas.microsoft.com/sharepoint/" =
xmlns:sps=3D"http://schemas.microsoft.com/sharepoint/soap/" =
xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance" =
xmlns:udcxf=3D"http://schemas.microsoft.com/data/udc/xmlfile" =
xmlns:wf=3D"http://schemas.microsoft.com/sharepoint/soap/workflow/" =
xmlns:mver=3D"http://schemas.openxmlformats.org/markup-compatibility/2006=
" xmlns:m=3D"http://schemas.microsoft.com/office/2004/12/omml" =
xmlns:mrels=3D"http://schemas.openxmlformats.org/package/2006/relationshi=
ps" =
xmlns:ex12t=3D"http://schemas.microsoft.com/exchange/services/2006/types"=
 =
xmlns:ex12m=3D"http://schemas.microsoft.com/exchange/services/2006/messag=
es" xmlns:Z=3D"urn:schemas-microsoft-com:" xmlns:st=3D"&#1;" =
xmlns=3D"http://www.w3.org/TR/REC-html40">

<head>

<meta name=3DGenerator content=3D"Microsoft Word 12 (filtered medium)">
<style>
<!--
 /* Font Definitions */
 @font-face
	{font-family:Calibri;
	panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
	{font-family:Tahoma;
	panose-1:2 11 6 4 3 5 4 4 2 4;}
 /* Style Definitions */
 p.MsoNormal, li.MsoNormal, div.MsoNormal
	{margin:0in;
	margin-bottom:.0001pt;
	font-size:12.0pt;
	font-family:"Times New Roman","serif";}
a:link, span.MsoHyperlink
	{mso-style-priority:99;
	color:blue;
	text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
	{mso-style-priority:99;
	color:purple;
	text-decoration:underline;}
span.EmailStyle17
	{mso-style-type:personal-reply;
	font-family:"Calibri","sans-serif";
	color:#1F497D;}
.MsoChpDefault
	{mso-style-type:export-only;}
@page Section1
	{size:8.5in 11.0in;
	margin:1.0in 1.0in 1.0in 1.0in;}
div.Section1
	{page:Section1;}
-->
</style>
<!--[if gte mso 9]><xml>
 <o:shapedefaults v:ext=3D"edit" spidmax=3D"1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
 <o:shapelayout v:ext=3D"edit">
  <o:idmap v:ext=3D"edit" data=3D"1" />
 </o:shapelayout></xml><![endif]-->
</head>

<body lang=3DEN-US link=3Dblue vlink=3Dpurple>

<div class=3DSection1>

<p class=3DMsoNormal><span =
style=3D'font-size:11.0pt;font-family:"Calibri","sans-serif";
color:#1F497D'>What kind of performance improvements are we talking =
about? Can
you provide some hard numbers?<o:p></o:p></span></p>

<p class=3DMsoNormal><span =
style=3D'font-size:11.0pt;font-family:"Calibri","sans-serif";
color:#1F497D'><o:p>&nbsp;</o:p></span></p>

<div style=3D'border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt =
0in 0in 0in'>

<p class=3DMsoNormal><b><span =
style=3D'font-size:10.0pt;font-family:"Tahoma","sans-serif"'>From:</span>=
</b><span
style=3D'font-size:10.0pt;font-family:"Tahoma","sans-serif"'>
[email protected]
[mailto:[email protected]] <b>On =
Behalf Of </b>Fabio
Maulo<br>
<b>Sent:</b> Monday, September 01, 2008 5:27 AM<br>
<b>To:</b> the NHibernate development list<br>
<b>Subject:</b> Re: [NHibernate-development] Speed improvement using =
compile
timegenerate proxies<o:p></o:p></span></p>

</div>

<p class=3DMsoNormal><o:p>&nbsp;</o:p></p>

<div>

<p class=3DMsoNormal style=3D'margin-bottom:12.0pt'>And please since NH =
have a
proxyfactoryfactory and ByteCodeProvider try to create separate =
injectable
implementation.<br>
Then we can test it in the core and hopeful use the new implementation =
as
default.<o:p></o:p></p>

<div>

<p class=3DMsoNormal>2008/9/1 &quot;Andr=E9s G. Aragoneses&quot; &lt;<a
href=3D"mailto:[email protected]">[email protected]</a>&gt;<o:p></o:p></p>

<p class=3DMsoNormal>+1<br>
<br>
I've had similar performance issues and I would vote for this to be<br>
included in NH Core vNext, so let's start creating a JIRA issue for =
it,<br>
right?<br>
<br>
Johan, wonderful research! Do you have rough benchmark numbers about =
the<br>
performance increase? A simple percentage number?<br>
<br>
Regards,<br>
<span style=3D'color:#888888'><br>
&nbsp; &nbsp; &nbsp; &nbsp;Andr=E9s</span><o:p></o:p></p>

<div>

<div>

<p class=3DMsoNormal><br>
<br>
Johan Kirsten wrote:<br>
&gt; Greetings<br>
&gt;<br>
&gt; I recently had the opportunity to move a project onto NHibernate. =
The<br>
&gt; project was using Gentle.NET. After moving the project onto =
NHibernate,<br>
&gt; I noticed that the application had become slower. For those not =
familiar<br>
&gt; with Gentle.NET, one of the biggest differences between Gentle.NET =
and<br>
&gt; NHibernate is the use of runtime generated proxies. Gentle.NET does =
not<br>
&gt; make use of runtime generated proxies, but rather method calls.<br>
&gt;<br>
&gt; An example of an NHibernate objects would be:<br>
&gt;<br>
&gt; * &nbsp; public class Invoice {<br>
&gt; &nbsp; &nbsp; &nbsp; private int _id;<br>
&gt; &nbsp; &nbsp; &nbsp; private string _reference;<br>
&gt; &nbsp; &nbsp; &nbsp; private Company _company;<br>
&gt; &nbsp; &nbsp; &nbsp; private IList&lt;InvoiceItem&gt; =
_invoiceItems;*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public Invoice() {<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public int Id {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get { return _id; }<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set { _id =3D value; }<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public virtual string Reference {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get { return _reference; }<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set { _reference =3D value; }<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public virtual Company Company {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get { return _company; }<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set { _company =3D value; }<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public virtual IList&lt;InvoiceItem&gt; =
InvoiceItems
{<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get { return _invoiceItems; }<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set { _invoiceItems =3D value; =
}<br>
&gt; &nbsp; &nbsp; &nbsp; }<br>
&gt; &nbsp; &nbsp;}*<br>
&gt; **<br>
&gt; * &nbsp; public class Company {<br>
&gt; &nbsp; &nbsp; &nbsp; private int _id;<br>
&gt; &nbsp; &nbsp; &nbsp; private string _name;*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public Company() {<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public int Id {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get { return _id; }<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set { _id =3D value; }<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public string Name {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get { return _name; }<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set { _name =3D value; }<br>
&gt; &nbsp; &nbsp; &nbsp; }<br>
&gt; &nbsp; &nbsp;}*<br>
&gt;<br>
&gt; The equivalent for Gentle.NET would be:<br>
&gt;<br>
&gt; * &nbsp; public class Invoice {<br>
&gt; &nbsp; &nbsp; &nbsp; private int _id;<br>
&gt; &nbsp; &nbsp; &nbsp; private string _reference;<br>
&gt; &nbsp; &nbsp; &nbsp; private int _companyKey;*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public Invoice() {<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public int Id {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get { return _id; }<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set { _id =3D value; }<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public virtual string Reference {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get { return _reference; }<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set { _reference =3D value; }<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public int CompanyKey {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get { return _companyKey; }<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set { _companyKey =3D value; =
}<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public Company GetCompany() {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Code that executes SQL and =
return
company for current invoice<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public static IList&lt;Invoice&gt; GetList() =
{<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Code that executes SQL and =
returns
all invoices<br>
&gt; &nbsp; &nbsp; &nbsp; }<br>
&gt; &nbsp; &nbsp;}*<br>
&gt; **<br>
&gt; * &nbsp; public class Company {<br>
&gt; &nbsp; &nbsp; &nbsp; private int _id;<br>
&gt; &nbsp; &nbsp; &nbsp; private string _name;*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public Company() {<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public int Id {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get { return _id; }<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set { _id =3D value; }<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public string Name {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get { return _name; }<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set { _name =3D value; }<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public IList&lt;Invoice&gt; GetInvoiceList() =
{<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Code that executes SQL and =
returns
invoices for current company<br>
&gt; &nbsp; &nbsp; &nbsp; }*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;public static IList&lt;Company&gt; GetList() =
{<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Code that executes SQL and =
returns
all companies<br>
&gt; &nbsp; &nbsp; &nbsp; }<br>
&gt; &nbsp; &nbsp;}*<br>
&gt;<br>
&gt; It is important to note that - in general and assuming lazy loading =
-<br>
&gt; Gentle.NET and NHibernate will execute the same SQL at the same =
point in<br>
&gt; code. For example the Gentle.NET code:<br>
&gt;<br>
&gt; * &nbsp; IList invoiceList =3D Invoice.GetList();<br>
&gt; &nbsp; &nbsp;foreach (Invoice invoice in invoiceList) {<br>
&gt; &nbsp; &nbsp; &nbsp; Company company =3D invoice.GetCompany();*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;// Print invoice and company information<br>
&gt; &nbsp; &nbsp;}*<br>
&gt;<br>
&gt; will request a list of invoices and the company for each =
invoice.<br>
&gt; NHibernate will do the same:<br>
&gt;<br>
&gt; * &nbsp; IList invoiceList =3D InvoiceDAO.GetList();<br>
&gt; &nbsp; &nbsp;foreach (Invoice invoice in invoiceList) {<br>
&gt; &nbsp; &nbsp; &nbsp; Company company =3D invoice.Company;*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp;// Print invoice and company information<br>
&gt; &nbsp; &nbsp;}*<br>
&gt;<br>
&gt; What I found was that the Gentle.NET code was faster. The only<br>
&gt; difference was the runtime generated proxies.<br>
&gt;<br>
&gt; The point I am trying to make is NHibernate takes a performance =
hit<br>
&gt; because of runtime generated proxies. I investigated and realised =
that<br>
&gt; the queries that were taking the longest were those retrieving =
lists of<br>
&gt; complex objects (objects containing other objects). These were =
the<br>
&gt; objects that used the most runtime generated proxies. I dived into =
the<br>
&gt; NHibernate code to understand why this is happening. What I =
discovered<br>
&gt; is that if you query a List of Invoices, NHibernate will compile a =
proxy<br>
&gt; for each Company of each row.<br>
&gt;<br>
&gt; To make it clear, for the first row in an Invoice results set,<br>
&gt; NHibernate (using Castle's dynamic proxy) generates a Company proxy =
type<br>
&gt; and then instantiates the proxy. For the second row, NHibernate =
again<br>
&gt; generates a Company proxy type and then instantiates the proxy.<br>
&gt; Therefore for a 100 invoices the same Company proxy type will =
be<br>
&gt; generated 100 times. After investigation I confirmed that this =
holds<br>
&gt; true for NH 1.2.1 and 2.0, although I suspect that NH 2.0 does =
not<br>
&gt; suffer as much due to optimization in Castle's new dynamic =
proxy.<br>
&gt;<br>
&gt; To confirm my suspisions I experimented with NH <a =
href=3D"http://1.2.1."
target=3D"_blank">1.2.1.</a> I altered the<br>
&gt; code of NHibernate.Proxy.CastleProxyFactory, which is responsible =
for<br>
&gt; proxy generation. I had it store the type on its first pass and =
then to<br>
&gt; use the stored type to instantiate each instance. I added the data =
member:<br>
&gt;<br>
&gt; * &nbsp; private System.Type _proxyType;*<br>
&gt;<br>
&gt; And altered the GetProxy method from:<br>
&gt;<br>
&gt; * &nbsp; public INHibernateProxy GetProxy(object id, =
ISessionImplementor<br>
&gt; session) {<br>
&gt; &nbsp; &nbsp; &nbsp; try {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CastleLazyInitializer initializer =
=3D new<br>
&gt; CastleLazyInitializer(_persistentClass, id, =
_getIdentifierMethod,<br>
&gt; _setIdentifierMethod, session);*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp; &nbsp; object generatedProxy =3D null;*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp; &nbsp; if (IsClassProxy) {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; generatedProxy =3D<br>
&gt; _proxyGenerator.CreateClassProxy(_persistentClass, _interfaces,<br>
&gt; initializer, false);<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; generatedProxy =3D
_proxyGenerator.CreateProxy(_interfaces,<br>
&gt; initializer, new object());<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp; &nbsp; initializer._constructed =3D =
true;<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return =
(INHibernateProxy)generatedProxy;<br>
&gt; &nbsp; &nbsp; &nbsp; }<br>
&gt; &nbsp; &nbsp; &nbsp; catch (Exception e) {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;log.Error(&quot;Creating a proxy
instance failed&quot;, e);<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new
HibernateException(&quot;Creating a proxy instance<br>
&gt; failed&quot;, e);<br>
&gt; &nbsp; &nbsp; &nbsp; }<br>
&gt; &nbsp; &nbsp;}*<br>
&gt;<br>
&gt; to:<br>
&gt;<br>
&gt; * &nbsp; public INHibernateProxy GetProxy(object id, =
ISessionImplementor<br>
&gt; session) {<br>
&gt; &nbsp; &nbsp; &nbsp; try {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CastleLazyInitializer initializer =
=3D new<br>
&gt; CastleLazyInitializer(_persistentClass, id, =
_getIdentifierMethod,<br>
&gt; _setIdentifierMethod, session);*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp; &nbsp; object generatedProxy =3D null;*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp; &nbsp; if (IsClassProxy) {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (_proxyType =3D=3D =
null)<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_proxyType =
=3D<br>
&gt; _proxyGenerator.ProxyBuilder.CreateClassProxy(_persistentClass,<br>
&gt; _interfaces);*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;generatedProxy =3D
Activator.CreateInstance(_proxyType,<br>
&gt; initializer);<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (_proxyType =3D=3D =
null)<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_proxyType =
=3D<br>
&gt; _proxyGenerator.ProxyBuilder.CreateInterfaceProxy(_interfaces,<br>
&gt; typeof(object));*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;generatedProxy =3D
Activator.CreateInstance(_proxyType, new<br>
&gt; object[] { initializer, new object() });<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}*<br>
&gt; **<br>
&gt; * &nbsp; &nbsp; &nbsp; &nbsp; initializer._constructed =3D =
true;<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return =
(INHibernateProxy)generatedProxy;<br>
&gt; &nbsp; &nbsp; &nbsp; }<br>
&gt; &nbsp; &nbsp; &nbsp; catch (Exception e) {<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;log.Error(&quot;Creating a proxy
instance failed&quot;, e);<br>
&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new
HibernateException(&quot;Creating a proxy instance<br>
&gt; failed&quot;, e);<br>
&gt; &nbsp; &nbsp; &nbsp; }<br>
&gt; &nbsp; &nbsp;}*<br>
&gt;<br>
&gt; This provided a speed improvement, but this isn't a solution. I do =
not<br>
&gt; want any delays at runtime due to proxy generation. I wanted to<br>
&gt; translate all of the types at startup. But for a lot of classes =
this<br>
&gt; would take too long and use too much memory. Then I found compile =
time<br>
&gt; generated proxies and it fit perfectly. Check out<br>
&gt; <a href=3D"http://code.google.com/p/nhibernateproxygenerator/"
target=3D"_blank">http://code.google.com/p/nhibernateproxygenerator/</a> =
by WC
Pierce. I<br>
&gt; downloaded the source code and altered it to compile multiple =
libraries<br>
&gt; (my domain is spread over multiple libraries). The library it =
generated<br>
&gt; contains a ProxyFactoryFactory which you can use by setting the<br>
&gt; &quot;proxyfactory.factory_class&quot; property in your config =
file:<br>
&gt;<br>
&gt; * &nbsp; &nbsp; &nbsp;&lt;property<br>
&gt; =
name=3D&quot;proxyfactory.factory_class&quot;&gt;StaticProxyFactoryFactor=
y,<br>
&gt; Library.Proxies&lt;/property&gt;*<br>
&gt;<br>
&gt; It worked amazingly well. The speed improved significantly. It does =
take<br>
&gt; a while to compile the proxies. Especially if you have a lot of =
classes.<br>
&gt; So I only plan to do this on deployment. I will continue to use =
runtime<br>
&gt; generated proxies in my debug environment. This solution seems to =
work<br>
&gt; very well. Please provide any thoughts and comments. I am =
especially<br>
&gt; interested in hearing any comments from people that can point out =
any<br>
&gt; serious downside to this approach. Are there specific reasons =
why<br>
&gt; runtime generated proxies are prefered over compile time =
generated<br>
&gt; proxies that I am not aware of?<br>
&gt;<br>
&gt; Finally I want to state that I hope that the NHibernate community =
will<br>
&gt; contemplate making compile time proxy generation a standard feature =
in<br>
&gt; the next release of NHibernate.<br>
&gt;<br>
&gt; Thanks<br>
&gt;<br>
&gt; Johan Kirsten<br>
&gt;<br>
&gt;<o:p></o:p></p>

</div>

</div>

<p class=3DMsoNormal>&gt;
------------------------------------------------------------------------<=
o:p></o:p></p>

<div>

<div>

<p class=3DMsoNormal>&gt;<br>
&gt; =
-------------------------------------------------------------------------=
<br>
&gt; This SF.Net email is sponsored by the Moblin Your Move Developer's
challenge<br>
&gt; Build the coolest Linux based applications with Moblin SDK &amp; =
win great
prizes<br>
&gt; Grand prize is a trip for two to an Open Source event anywhere in =
the
world<br>
&gt; <a =
href=3D"http://moblin-contest.org/redirect.php?banner_id=3D100&amp;url=3D=
/"
target=3D"_blank">http://moblin-contest.org/redirect.php?banner_id=3D100&=
amp;url=3D/</a><br>
&gt;<br>
&gt;<br>
&gt; =
------------------------------------------------------------------------<=
br>
&gt;<br>
&gt; _______________________________________________<br>
&gt; Nhibernate-development mailing list<br>
&gt; <a =
href=3D"mailto:[email protected]">Nhibernate-d=
[email protected]</a><br>
&gt; <a
href=3D"https://lists.sourceforge.net/lists/listinfo/nhibernate-developme=
nt"
target=3D"_blank">https://lists.sourceforge.net/lists/listinfo/nhibernate=
-development</a><br>
<br>
<br>
-------------------------------------------------------------------------=
<br>
This SF.Net email is sponsored by the Moblin Your Move Developer's =
challenge<br>
Build the coolest Linux based applications with Moblin SDK &amp; win =
great
prizes<br>
Grand prize is a trip for two to an Open Source event anywhere in the =
world<br>
<a =
href=3D"http://moblin-contest.org/redirect.php?banner_id=3D100&amp;url=3D=
/"
target=3D"_blank">http://moblin-contest.org/redirect.php?banner_id=3D100&=
amp;url=3D/</a><br>
_______________________________________________<br>
Nhibernate-development mailing list<br>
<a =
href=3D"mailto:[email protected]">Nhibernate-d=
[email protected]</a><br>
<a =
href=3D"https://lists.sourceforge.net/lists/listinfo/nhibernate-developme=
nt"
target=3D"_blank">https://lists.sourceforge.net/lists/listinfo/nhibernate=
-development</a><o:p></o:p></p>

</div>

</div>

</div>

<p class=3DMsoNormal><br>
<br clear=3Dall>
<br>
-- <br>
Fabio Maulo<o:p></o:p></p>

</div>

</div>

</body>

</html>

------_=_NextPart_001_01C90C50.22F350EF--


--===============1042934962==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
--===============1042934962==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Nhibernate-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/nhibernate-development

--===============1042934962==--