<?xml version="1.0" encoding="UTF-8"?> <!-- Application Description Language framework adl2controllerclasses.xsl (c) 2007 Cygnet Solutions Ltd Transform ADL into (partial) controller classes $Author: sb $ $Revision: 1.29 $ $Date: 2009-02-20 15:25:29 $ --> <!-- WARNING WARNING WARNING: Do NOT reformat this file! Whitespace (or lack of it) is significant! --> <xsl:stylesheet version="1.0" xmlns="http://libs.cygnets.co.uk/adl/1.1/" xmlns:adl="http://libs.cygnets.co.uk/adl/1.1/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="urn:schemas-microsoft-com:xslt" extension-element-prefixes="exsl"> <xsl:include href="csharp-type-include.xslt"/> <xsl:include href="permissions-include.xslt"/> <xsl:output encoding="UTF-8" method="text"/> <!-- The locale for which these controllers are generated TODO: Controllers should NOT be locale specific. Instead, the controller should render views and generate messages based on the client's locale. However, there may still need to be a concept of a 'default locale', for when we don't have messages which suit the client's locale --> <xsl:param name="locale" select="en-UK"/> <!-- bug 1896 : boilerplate text in views should be tailored to the locale of the expected user. Unfortunately I haven't yet worked out how to do conditional includes in XSLT, so this is a step on the way to a solution, not a solution in itself. --> <xsl:include href="i18n-en-GB-include.xslt"/> <!-- The C# namespace within which I shall generate controllers --> <xsl:param name="controllerns" select="Unset"/> <!-- The C# namespace used by the entities for this project --> <xsl:param name="entityns" select="Unset"/> <!-- Whether to authenticate at application or at database layer. If not 'Application', then 'Database'. --> <xsl:param name="authentication-layer" select="Application"/> <!-- the name and version of the product being built --> <xsl:param name="product-version" select="'Application Description Language Framework'"/> <!-- bug 1800 : the name of the Velocity layout to use --> <xsl:param name="layout-name" select="adl-default-layout"/> <!-- bug 1800 : the name of the Velocity rescue view to use --> <xsl:param name="rescue-name"/> <!-- bug 1800 : the name of the area (i.e. URL path part) to use --> <xsl:param name="area-name"/> <xsl:template match="adl:application"> /* ---- [ cut here: next file '<xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/>.auto.cs'] ---------------- */ //------------------------------------------------------------------ // // <xsl:value-of select="$product-version"/> // <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller.auto.cs')"/> // // (c) 2007 Cygnet Solutions Ltd // // Automatically generated abstract super class for controllers for the // <xsl:value-of select="/adl:application/@name"/> application; generated using // adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.29 $', 10)"/> // // <xsl:value-of select="/adl:application/@revision"/> // // This file is automatically generated; DO NOT EDIT IT. // //------------------------------------------------------------------ using System; using System.Data; using System.Collections.Generic; using System.Data.SqlClient; using NHibernate; using NHibernate.Expression; using Cygnet.DBAuth; using Cygnet.Web.Controllers; using Cygnet.Web.Helpers; using Castle.MonoRail.Framework; using <xsl:value-of select="$entityns"/>; namespace <xsl:value-of select="$controllerns"/> { /// <summary> /// Automatically generated abstract super class for controllers for the /// <xsl:value-of select="/adl:application/@name"/> application /// /// DO NOT EDIT THIS FILE! /// </summary> [ <!-- in the longer term, all the helpers which a given project needs which not every project needs should be listed here, with appropriate 'xsl:if' wrappers. --> Helper(typeof(FormatterHelper), "t"), Helper(typeof(SecurityHelper), "SecurityHelper") ] public abstract partial class <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/> : BaseController { <xsl:choose> <xsl:when test="$authentication-layer = 'Application'"/> <xsl:when test="$authentication-layer = 'Database'"> /* authentication layer is requested to be 'database', but in fact database-layer authentication does not work well with NHibernate so this is being ignored. */ </xsl:when> <xsl:otherwise> <xsl:message terminate="yes"> ADL: ERROR: invalid value (<xsl:value-of select="$authentication-layer"/>) provided for authentication-layer </xsl:message> </xsl:otherwise> </xsl:choose> <xsl:for-each select="//adl:entity"> /// <summary> /// Return a list of all instances of <xsl:value-of select="@name"/> for use in menus, etc; /// </summary> protected IList<<xsl:value-of select="concat( $entityns, '.', @name)"/>> <xsl:value-of select="concat( 'FetchAll', @name)"/>( ) { IList<<xsl:value-of select="concat( $entityns, '.', @name)"/>> result = new List<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); <xsl:variable name="readgroups"> <xsl:call-template name="entity-read-groups"> <xsl:with-param name="entity" select="."/> </xsl:call-template> </xsl:variable> <xsl:if test="$authentication-layer = 'Database'"> if ( <xsl:for-each select="exsl:node-set( $readgroups)/*"> InGroup( "<xsl:value-of select="./@name"/>")<xsl:if test="position() != last()">||</xsl:if> </xsl:for-each> ){ </xsl:if> result = GetDBSession().CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>)) <xsl:for-each select="descendant::adl:property[@distinct='user']"> .AddOrder( <xsl:value-of select="concat('new Order( "', @name, '", true)')"/>) </xsl:for-each> .SetCacheable( true) .SetCacheRegion( "<xsl:value-of select="/adl:application/@name"/>") .List<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); <xsl:if test="$authentication-layer != 'Application'"> } </xsl:if> return result; } </xsl:for-each> } } <xsl:apply-templates select="adl:entity"/> </xsl:template> <!-- Don't bother generating anything for foreign entities --> <xsl:template match="adl:entity[@foreign='true']"/> <xsl:template match="adl:entity"> /* * Not generating controller for entity <xsl:value-of select="@name"/>, * as it has no forms, pages or lists. */ </xsl:template> <xsl:template match="adl:entity[adl:form|adl:page|adl:list]"> /* ---- [ cut here: next file '<xsl:value-of select="@name"/>Controller.auto.cs'] ---------------- */ //------------------------------------------------------------------ // // <xsl:value-of select="$product-version"/> // <xsl:value-of select="@name"/>Controller.auto.cs // // (c) 2007 Cygnet Solutions Ltd // // Controller for auto-generated forms for editing <xsl:value-of select="@name"/>s // Automatically generated from application description using // adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.29 $', 10)"/> // // This file is automatically generated; DO NOT EDIT IT. // //------------------------------------------------------------------ using System; using System.Data; using System.Collections.Generic; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using Castle.MonoRail.Framework.Helpers; using Cygnet.Exceptions; using Cygnet.Web.Helpers; using Cygnet.Web.Controllers; using Cygnet.Web.SmartControls; using NHibernate; using NHibernate.Expression; using Castle.MonoRail.Framework; using Iesi.Collections.Generic; using <xsl:value-of select="$entityns"/>; namespace <xsl:value-of select="$controllerns"/> { /// <summary> /// Automatically generated partial controller class following 'thin controller' /// strategy, for entity <xsl:value-of select="@name"/>. Note that part of this /// class may be defined in a separate file called /// <xsl:value-of select="@name"/>Controller.manual.cs, q.v. /// /// DO NOT EDIT THIS FILE! /// </summary> [ <xsl:if test="$layout-name"> Layout("<xsl:value-of select="$layout-name"/>"), </xsl:if> <xsl:if test="$rescue-name"> Rescue("<xsl:value-of select="$rescue-name"/>"), </xsl:if> ControllerDetails("<xsl:value-of select="@name"/>", Area = "<xsl:value-of select="$area-name"/>"), Helper(typeof(StylesHelper), "StylesHelper"), Helper(typeof(<xsl:value-of select="concat( @name, 'FieldHelper')"/>), "<xsl:value-of select="concat( @name, 'FieldHelper')"/>") ] public partial class <xsl:value-of select="concat( @name, 'Controller')"/> : <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/> { protected class <xsl:value-of select="concat( @name, 'FieldHelper')"/> : SmartFormHelper { public <xsl:value-of select="concat( @name, 'FieldHelper')"/>() { <xsl:for-each select="descendant::adl:property[@type='entity']"> <xsl:variable name="entityname" select="@entity"/> <xsl:variable name="entity" select="//adl:entity[@name=$entityname]"/> <xsl:choose> <xsl:when test="$entity/@foreign='true'"> /* Entity <xsl:value-of select="$entityname"/> is foreign..? */ <xsl:variable name="foreignkey" select="$entity/adl:key/adl:property[position()=1]/@name"/> <xsl:variable name="userident"> <xsl:choose> <xsl:when test="$entity//adl:property[@distinct='user' or @distinct='all']"> <xsl:value-of select="$entity//adl:property[@distinct='user' or @distinct='all'][position()=1]/@name"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$foreignkey"/> </xsl:otherwise> </xsl:choose> </xsl:variable> Register<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "", new TypeMenuControl<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "<xsl:value-of select="$foreignkey"/>","<xsl:value-of select="$userident"/>")); </xsl:when> <xsl:otherwise> Register<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "", EntityMenuControl<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>.Instance); </xsl:otherwise> </xsl:choose> </xsl:for-each> <xsl:for-each select="descendant::adl:property[@type='list']"> <xsl:variable name="entityname" select="@entity"/> Register<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "", EntityShuffleControl<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>.Instance); </xsl:for-each> } } <xsl:if test="adl:property[@type='message']"> /// <summary> /// Temporary hack to sort a problem with uninitialised messages /// </summary> public void fixupMessages() { ISession hibernator = GetDBSession(); ICollection<<xsl:value-of select="concat($entityns, '.', @name)"/>> instances = hibernator.CreateCriteria( typeof( <xsl:value-of select="concat($entityns, '.', @name)"/>)) .List<<xsl:value-of select="concat($entityns, '.', @name)"/>>(); foreach ( <xsl:value-of select="concat($entityns, '.', @name)"/> instance in instances) { <xsl:for-each select="adl:property[@type='message']"> if ( <xsl:value-of select="concat( 'instance.', @name)"/> == null || <xsl:value-of select="concat( 'instance.', @name, '.MessageId')"/> == 0 ){ <xsl:value-of select="concat( 'instance.', @name)"/> = new Message(); hibernator.Save( <xsl:value-of select="concat( 'instance.', @name)"/>); } </xsl:for-each> hibernator.Save( instance); } hibernator.Flush(); <xsl:if test="adl:list[@name='list']"> list(); </xsl:if> } </xsl:if> <xsl:if test="adl:form"> <!-- unless there's at least one form, we won't generate a 'store' method --> /// <summary> /// Store the record represented by the parameters passed in an HTTP service /// Without Id -> it's new, I create a new persistent object; /// With Id -> it's existing, I update the existing persistent object. /// NOTE: Should only be called from a handler for method 'POST', never 'GET'. /// </summary> private void Store() { ISession hibernator = GetDBSession(); List<string> messages = new List<string>(); /* A 'newborn' instance can be updated even if the current user doesn't have * update permissions, seeing that we use an update operation to set the * field values and save the entity. */ Boolean isnewborn = false; /* the instance (record) of type <xsl:value-of select="@name"/> we're dealing with */ <xsl:value-of select="concat($entityns, '.', @name)"/> record = null; try { <xsl:if test="adl:property[@distinct='system' or @distinct='all']"> /* a criteria object to use in distinctness checks */ ICriteria matchCriteria = null; </xsl:if> record = FetchRecord( hibernator); <xsl:apply-templates select="adl:property"/> if ( HasNoErrors()) { if ( record == null) { /* it seems to be new, create persistent object - if the user is permitted to */ AssertUserCanCreate(); try { if ( AllKeys()) { record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(<xsl:for-each select="adl:key/adl:property"> <xsl:variable name="basetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$basetype='integer'"> Int32.Parse( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]) </xsl:when> <xsl:when test="$basetype='entity'"> <!-- Maybe TODO: this doesn't work recursively - if an entity has a key which is an entity and the key of that entity is an entity, you're on your own, mate! --> <xsl:variable name="keyentity" select="@entity"/> <xsl:variable name="keyenttype"> <xsl:call-template name="primary-key-csharp-type"> <xsl:with-param name="entity" select="//adl:entity[@name=$keyentity]"/> </xsl:call-template> </xsl:variable> hibernator.CreateCriteria( typeof( <xsl:value-of select="concat( $entityns, '.', $keyentity)"/>)) <xsl:call-template name="add-hibernate-expression-eq"> <xsl:with-param name="property" select="//adl:entity[@name=$keyentity]/adl:key/adl:property[position()=1]"/> <xsl:with-param name="value"> Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"] </xsl:with-param> </xsl:call-template> .UniqueResult<<xsl:value-of select="concat( $entityns, '.', $keyentity)"/>>() </xsl:when> <xsl:otherwise> Form["<xsl:value-of select="concat( 'instance.', @name)"/>"] </xsl:otherwise> </xsl:choose> <xsl:choose> <xsl:when test="position() = last()"/> <xsl:otherwise>, </xsl:otherwise> </xsl:choose> </xsl:for-each>); } else { record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(); } } catch ( FormatException) { /* failed to parse a number - not wholly unexpected, since it's most likely * that an empty string was passed in */ record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(); } catch ( NullReferenceException) { /* again, probably more normal than otherwise */ record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(); } messages.Add( "New <xsl:value-of select="@name"/> record created"); isnewborn = true; } if ( record != null) { /* a transaction to ensure our database operations are atomic */ ITransaction tx = null; if ( ! isnewborn) { /* isnewborn cannot be true unless we've already checked user can create * so no need to do it again here */ AssertUserCanUpdate(); } try { /* begin our atomic transaction */ tx = hibernator.BeginTransaction(); /* actually update the record */ BindObjectInstance( record, ParamStore.Form, "instance"); <xsl:if test="descendant::adl:property[@type='message']"> /* there is at least one slot whose value is an internationalised message; * if these have yet to be initialised they must be handled specially */ Locale locale = GetBestLocaleForUser(); <xsl:for-each select="descendant::adl:property[@type='message']"> if ( ! String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])){ /* there's an uninitialised message for this slot */ Message mess = record.<xsl:value-of select="@name"/>; if ( mess == null) { mess = new Message(); } hibernator.Save( mess); Translation trans = mess.GetTranslationObject( locale, hibernator); if ( trans == null) { trans = new Translation( mess, locale); } trans.MessageText = Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]; record.<xsl:value-of select="@name"/> = mess; hibernator.Save( trans); } </xsl:for-each> </xsl:if> <xsl:for-each select="descendant::adl:property[@type='entity']"> /* for properties of type 'entity', it should not be necessary to do anything * special - BindObjectInstance /should/ do it all. Unfortunately it sometimes * doesn't, and I haven't yet characterised why not. */ <xsl:variable name="entityname" select="@entity"/> <xsl:choose> <xsl:when test="//adl:entity[@name=$entityname]"> if ( ! String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]) && ! EntityMenuControl<<xsl:value-of select="concat( $entityns, '.', @entity)"/>>.NULLMARKER.Equals ( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) { record.<xsl:value-of select="@name"/> = <xsl:call-template name="fetch-property-instance"> <xsl:with-param name="property" select="."/> <xsl:with-param name="value"> Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"] </xsl:with-param> </xsl:call-template>; } </xsl:when> <xsl:otherwise> <xsl:message terminate="yes"> ADL: ERROR: Could not fix up value of <xsl:value-of select="@name "/>, because no entity was found called <xsl:value-of select="$entityname"/> </xsl:message> </xsl:otherwise> </xsl:choose> </xsl:for-each> <xsl:for-each select="descendant::adl:property[@type='link']"> <xsl:variable name="farentityname" select="@entity"/> <xsl:variable name="entity" select="//adl:entity[@name=$farentityname]"/> <xsl:variable name="farkey" select="$entity/adl:key/adl:property[position()=1]/@name"/> <xsl:variable name="farkeybasetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="//adl:entity[@name=$farentityname]/adl:key/adl:property[position()=1]"/> </xsl:call-template> </xsl:variable> <xsl:variable name="deletegroups"> <xsl:call-template name="entity-delete-groups"> <xsl:with-param name="entity" select="$entity"/> </xsl:call-template> </xsl:variable> /* to update a link table which has no other data than the near and far keys, it is * sufficient to smash the existing values and create new ones. It's also a lot easier! */ <xsl:if test="$authentication-layer = 'Database'"> if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*"> InGroup( "<xsl:value-of select="./@name"/>") || </xsl:for-each> false) { /* however, we cannot do anything unless we have delete permissions on the table, so * should not try. */ </xsl:if> string[] <xsl:value-of select="concat(@name, 'Values')"/> = Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>"); /* update the linking table for my <xsl:value-of select="@name"/>; first smash the old values */ if ( <xsl:value-of select="concat( 'record.', @name)"/> != null) { <xsl:value-of select="concat( 'record.', @name)"/>.Clear(); } else { <xsl:value-of select="concat( 'record.', @name)"/> = new HashedSet<<xsl:value-of select="concat( $entityns, '.', @entity)"/>>(); } /* if ( <xsl:value-of select="concat( 'record.', @name)"/> != null) */ if ( <xsl:value-of select="concat(@name, 'Values')"/> != null) { /* then reinstate the values from the indexes passed */ foreach ( string index in <xsl:value-of select="concat(@name, 'Values')"/>) { <xsl:value-of select="concat( 'record.', @name)"/>.Add( hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @entity)"/>)) <xsl:call-template name="add-hibernate-expression-eq"> <xsl:with-param name="property" select="//adl:entity[@name=$farentityname]/adl:key/adl:property[position()=1]"/> <xsl:with-param name="value" select="'index'"/> </xsl:call-template> .UniqueResult<<xsl:value-of select="concat( $entityns, '.', @entity)"/>>()); } /* foreach ( string index in <xsl:value-of select="concat(@name, 'Values')"/>) */ } /* if ( <xsl:value-of select="concat(@name, 'Values')"/> != null) */ <xsl:if test="$authentication-layer = 'Database'"> } /* if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*"> InGroup( "<xsl:value-of select="./@name"/>") || </xsl:for-each> false) */ </xsl:if> </xsl:for-each> <xsl:for-each select="descendant::adl:property[@type='list']"> <xsl:variable name="farentityname" select="@entity"/> <xsl:variable name="entity" select="//adl:entity[@name=$farentityname]"/> <xsl:variable name="farkey" select="$entity/adl:key/adl:property[position()=1]/@name"/> <xsl:variable name="farkeybasetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="//adl:entity[@name=$farentityname]/adl:key/adl:property[position()=1]"/> </xsl:call-template> </xsl:variable> <xsl:variable name="foreignkey"> <xsl:choose> <xsl:when test="@farkey"> <xsl:value-of select="@farkey"/> </xsl:when> <xsl:otherwise> <!-- If I haven't been told what the far side foreign key is, assume it has the name of my entity --> <xsl:value-of select="ancestor::adl:entity/@name"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="deletegroups"> <xsl:call-template name="entity-delete-groups"> <xsl:with-param name="entity" select="$entity"/> </xsl:call-template> </xsl:variable> /* with a list we cannot just smash the old values! Instead we need to check * each one and exclude it if no longer required; */ <xsl:if test="$authentication-layer = 'Database'"> if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*"> InGroup( "<xsl:value-of select="./@name"/>") || </xsl:for-each> false) { /* but once again only if we can delete and create entities at the far end. */ </xsl:if> if ( Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>") != null) { string[] <xsl:value-of select="concat(@name, 'Values')"/> = Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>"); /* updating <xsl:value-of select="@name"/> child records; first remove any not on the submitted list */ foreach ( <xsl:value-of select="@entity"/> item in record.<xsl:value-of select="@name"/>) { String itemId = item.KeyString; bool found = false; foreach ( string index in <xsl:value-of select="concat(@name, 'Values')"/>) { if ( index.Equals( itemId)) { found = true; break; } } /* foreach ( string index... */ if ( ! found) { record.<xsl:value-of select="@name"/>.Remove( item); break; } } /* foreach ( <xsl:value-of select="@entity"/> item ... */ /* then add any on the included list which are not already members */ foreach ( string index in <xsl:value-of select="concat(@name, 'Values')"/>) { <xsl:value-of select="concat( $entityns, '.', @entity)"/> item = hibernator.CreateCriteria(typeof(<xsl:value-of select="@entity"/>)) <xsl:call-template name="add-hibernate-expression-eq"> <xsl:with-param name="property" select="//adl:entity[@name=$farentityname]/adl:key/adl:property[position()=1]"/> <xsl:with-param name="value" select="'index'"/> </xsl:call-template> .UniqueResult<<xsl:value-of select="concat( $entityns, '.', @entity)"/>>(); if ( ! record.<xsl:value-of select="@name"/>.Contains( item)) { /* check whether it's already a child of another <xsl:value-of select="ancestor::adl:entity/@name"/> * and, if it is, remove it */ <xsl:value-of select="concat( $entityns, '.', ancestor::adl:entity/@name)"/> oldparent = <xsl:value-of select="concat( 'item.', $foreignkey)"/>; if ( oldparent != null) { oldparent.<xsl:value-of select="@name"/>.Remove( item); hibernator.Save( oldparent); } /* then add it to my <xsl:value-of select="@name"/> */ record.<xsl:value-of select="@name"/>.Add( item); <xsl:value-of select="concat( 'item.', $foreignkey)"/> = record; hibernator.Save( item); } } /* foreach ( string index... */ } /* if ( Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>") != null) */ <xsl:if test="$authentication-layer = 'Database'"> } /* if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*">InGroup( "<xsl:value-of select="./@name"/>") ||</xsl:for-each> false) */ </xsl:if> </xsl:for-each> /* write the record to the database, in order to guarantee we have a valid key */ hibernator.Save(record); hibernator.Flush(); tx.Commit(); messages.Add( "<xsl:call-template name="i18n-record-saved"/>"); } /* try actually commit */ catch ( Exception any) { messages.Add( "<xsl:call-template name="i18n-record-not-saved"/>"); AddError( any); try { tx.Rollback(); } catch ( ObjectDisposedException ode) { AddError( ode); } } /* catch ( Exception any) */ } /* if ( record != null) */ else { throw new ApplicationException( String.Format( "<xsl:call-template name="i18n-record-not-found"> <xsl:with-param name="entity-name" select="@name"/> </xsl:call-template>")); } } /* if ( HasNoErrors()) */ } /* try */ catch ( DataSuitabilityException dse) { AddError( dse); } catch ( ApplicationException axe) { AddError( axe.Message); } if ( ! HasNoErrors()) { /* the session may be polluted; create a new session */ CloseDBSession(); hibernator = GetDBSession(); record = FetchRecord( hibernator); } /* if ( ! HasNoErrors()) */ <xsl:value-of select="concat( 'this.',adl:form[position()=1]/@name)"/>( record); } </xsl:if> <xsl:if test="adl:form"> <!-- unless there's at least one form, we won't generate a 'delete' method --> /// <summary> /// Actually delete the selected record /// </summary> [AccessibleThrough(Verb.Post)] public void Delete() { AssertUserCanDelete(); ISession hibernator = GetDBSession(); if ( "true".Equals( Params["reallydelete"])) { <xsl:value-of select="concat($entityns, '.', @name)"/> record = FetchRecord( hibernator); if ( record != null) { hibernator.Delete( record); hibernator.Flush(); } else { throw new ApplicationException( "No such record?"); } } <xsl:choose> <xsl:when test="adl:list"> Redirect( "<xsl:value-of select="concat(adl:list[position()=1]/@name, '.rails')"/>"); </xsl:when> <xsl:otherwise> Redirect( FormsAuthentication.DefaultUrl); </xsl:otherwise> </xsl:choose> } </xsl:if> <xsl:apply-templates select="adl:form"/> <xsl:if test="adl:list"> <xsl:variable name="listname" select="adl:list[position()=1]/@name"/> <xsl:apply-templates select="adl:list"/> /// <summary> /// list all instances of this entity to allow the user to select one for editing /// this method invokes the default list view - which is probably what you want unless /// you've a special reason for doing something different /// </summary> public void InternalShowList() { InternalShowList( "<xsl:value-of select="$listname"/>"); } /// <summary> /// list all instances of this entity to allow the user to select one for editing /// </summary> /// <param name="view">The name of the list view to show</param> public void InternalShowList( String view) { AssertUserCanRead(); ISession hibernator = GetDBSession(); ICriteria search = hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>)); <xsl:for-each select="adl:property"> <xsl:variable name="base-type"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$base-type='boolean'"/> <xsl:when test="$base-type='link'"/> <xsl:when test="$base-type='list'"/> <xsl:otherwise> if ( ! String.IsNullOrEmpty( Params[ "<xsl:value-of select="concat( 'search_', @name)"/>"])) { search<xsl:call-template name="add-hibernate-expression-like"> <xsl:with-param name="property" select="."/> <xsl:with-param name="value">Params["<xsl:value-of select="concat( 'search_', @name)"/>"]</xsl:with-param> </xsl:call-template>; } </xsl:otherwise> </xsl:choose> </xsl:for-each> <xsl:for-each select="adl:property[@distinct='user' or @distinct='all']"> search.AddOrder(<xsl:value-of select="concat( ' new Order( "', @name, '", true)')"/>); </xsl:for-each> IList<<xsl:value-of select="concat( $entityns, '.', @name)"/>> instances = search.List<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); PropertyBag["instances"] = PaginationHelper.CreatePagination( this, instances, 25); RenderViewWithFailover(view + ".vm", view + ".auto.vm"); } </xsl:if> /// <summary> /// Check whether values for all my keys are available in the form fields /// </summary> protected bool AllKeys() { /* whether we have valid values for all the key fields */ bool result = true; <xsl:for-each select="adl:key/adl:property"> if ( String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) { result = false; } else if ( "<xsl:value-of select="concat('$instance.', @name)"/>".Equals( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) { /* nasty artefact of NVelocity forms - default 'null value' is dollar followed by fieldname */ result = false; } </xsl:for-each> return result; } /// <summary> /// Fetch the record represented by the values in the current Form /// </summary> protected <xsl:value-of select="concat($entityns, '.', @name)"/> FetchRecord(ISession hibernator) { /* the instance (record) of type <xsl:value-of select="@name"/> we're dealing with */ <xsl:value-of select="concat($entityns, '.', @name)"/> record = null; if ( AllKeys()){ /* it's (probably) existing, retrieve it */ record = hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>)) <xsl:for-each select="adl:key/adl:property"> <xsl:call-template name="add-hibernate-expression-eq"> <xsl:with-param name="property" select="."/> <xsl:with-param name="value">Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]</xsl:with-param> </xsl:call-template> </xsl:for-each> .UniqueResult<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); } return record; } } } /* ---- [ cut here: next file 'junk'] ------------------------- */ </xsl:template> <xsl:template match="adl:property"> <xsl:if test="@required='true'"> if ( <xsl:if test="@immutable='true'"> (record == null || <xsl:value-of select="concat( 'record.', @name)"/> == null) && </xsl:if> String.IsNullOrEmpty( Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>" ])) { AddError( <xsl:choose> <xsl:when test="adl:ifmissing[@locale=$locale]"> <xsl:apply-templates select="adl:ifmissing[@locale=$locale]"/> </xsl:when> <xsl:otherwise> "<xsl:call-template name="i18n-value-required"> <xsl:with-param name="property-name" select="@name"/> </xsl:call-template>" </xsl:otherwise> </xsl:choose>); } </xsl:if> <xsl:if test="@distinct='system' or @distinct='all'"> <xsl:call-template name="check-property-value-distinct"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:if> </xsl:template> <xsl:template match="adl:ifmissing"> "<xsl:value-of select="normalize-space(.)"/>" </xsl:template> <xsl:template match="adl:form"> /// <summary> /// Handle the submission of the form named <xsl:value-of select="@name"/> /// </summary> [AccessibleThrough(Verb.Post)] public void <xsl:value-of select="concat( @name, 'SubmitHandler')"/>( ) { string command = Form[ "command"]; if ( command == null) { throw new Exception( "<xsl:call-template name="i18n-command-not-found"/>"); } else <xsl:for-each select=".//adl:verb"> if ( command.Equals( "<xsl:value-of select="@verb"/>")) { /* NOTE: You must write an implementation of this verb in a * manually maintained partial class file for this class */ <xsl:value-of select="@verb"/>(); } else </xsl:for-each> if ( command.Equals( "delete")) { ISession hibernator = GetDBSession(); <xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/> record = FetchRecord( hibernator); TypedPropertyBag = new { instance = record }; RenderViewWithFailover( "maybedelete.vm", "maybedelete.auto.vm"); } else if ( command.Equals( "store")) { Store(); } else { throw new Exception( String.Format("<xsl:call-template name="i18n-command-not-found"> <xsl:with-param name="command" select="'{0}'"/> </xsl:call-template>", command)); } } /// <summary> /// Show the form named <xsl:value-of select="@name"/>, with no existing record /// </summary> [AccessibleThrough(Verb.Get)] public void <xsl:value-of select="@name"/>( ) { AssertUserCanRead(); <xsl:value-of select="ancestor::adl:entity/@name"/> record = null; <xsl:value-of select="concat( 'this.', @name)"/>( record); } <xsl:variable name="form" select="."/> <xsl:for-each select="ancestor::adl:entity/adl:property[ @type='entity']"> /// <summary> /// Show the form named <xsl:value-of select="$form/@name"/>, for a new record, but with the /// value for <xsl:value-of select="@name"/> already predetermined /// </summary> [AccessibleThrough(Verb.Get)] public void <xsl:value-of select="concat($form/@name, 'With', @name)"/>( string <xsl:value-of select="@name"/>) { AssertUserCanRead(); ISession hibernator = GetDBSession(); <xsl:value-of select="ancestor::adl:entity/@name"/> record = new <xsl:value-of select="ancestor::adl:entity/@name"/>(); record.<xsl:value-of select="@name"/> = <xsl:call-template name="fetch-property-instance"> <xsl:with-param name="property" select="."/> <xsl:with-param name="value" select="@name"/> </xsl:call-template>; <xsl:value-of select="concat( 'this.', $form/@name)"/>( record); } </xsl:for-each> /// <summary> /// Show the form named <xsl:value-of select="@name"/>, containing the indicated record. As /// the primary key of the record is itself an entity, we need to first fetch that entity /// </summary> <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> <xsl:choose> <xsl:when test="@type='entity'"> /// <param name="<xsl:value-of select="@name"/>">the key value of the key value of the record to show</param> </xsl:when> <xsl:otherwise> /// <param name="<xsl:value-of select="@name"/>">the key value of the record to show</param> </xsl:otherwise> </xsl:choose> </xsl:for-each> [AccessibleThrough(Verb.Get)] public void <xsl:value-of select="@name"/>( <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> <!-- all args are passed as string because that's what hibernate-expression-eq expects --> string <xsl:value-of select="concat( ' ', @name)"/> <xsl:if test="not( position() = last())">,</xsl:if> </xsl:for-each>) { ISession hibernator = GetDBSession(); <xsl:value-of select="concat( 'this.', @name)"/>( hibernator.CreateCriteria( typeof(<xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/>)) <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> <xsl:call-template name="add-hibernate-expression-eq"> <xsl:with-param name="property" select="."/> <xsl:with-param name="value" select="@name"/> </xsl:call-template> </xsl:for-each> .UniqueResult<<xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/>>()); } /// <summary> /// Show the form named <xsl:value-of select="@name"/>, containing the indicated record /// </summary> /// <param name="record">the record to show</param> protected void <xsl:value-of select="@name"/>( <xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/> record) { ISession hibernator = GetDBSession(); TypedPropertyBag = new { <xsl:call-template name="formmenus"> <xsl:with-param name="form" select="."/> </xsl:call-template> instance = record }; RenderViewWithFailover("<xsl:value-of select="concat( @name, '.vm')"/>", "<xsl:value-of select="concat( @name, '.auto.vm')"/>"); } </xsl:template> <xsl:template match="adl:list"> /// <summary> /// list all instances of this entity to allow the user to select one /// this method invokes the named view. /// </summary> public void <xsl:value-of select="@name"/>() { InternalShowList( "<xsl:value-of select="@name"/>"); } </xsl:template> <xsl:template match="adl:documentation"> /* <xsl:apply-templates/> */ </xsl:template> <xsl:template match="adl:key"> <!-- the key shouldn't be matched directly - at least, not in this implementation --> </xsl:template> <!-- for properties with @distinct='all' or @distinct='system', check that values are indeed distinct --> <xsl:template name="check-property-value-distinct"> <xsl:param name="property"/> <xsl:variable name="basetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$property/ancestor::adl:key and not( $property/ancestor::adl:entity/adl:key[position()=2])"> <!-- if I'm the property of a key field and it is the only key field of my entity then it is pointless trying to establish my distinctness --> </xsl:when> <xsl:when test="$property/@distinct = 'system' or $property/@distinct='all'"> /* <xsl:value-of select="$property/@name"/> should be distinct: check that it is */ matchCriteria = hibernator.CreateCriteria(typeof(<xsl:value-of select="$property/ancestor::adl:entity/@name"/>)); matchCriteria<xsl:call-template name="add-hibernate-expression-eq"> <xsl:with-param name="property" select="$property"/> <xsl:with-param name="value"> Form["<xsl:value-of select="concat( 'instance.', @name)"/>"] </xsl:with-param> </xsl:call-template>; if ( record != null) { /* i.e. we do have values for each of our key fields... */ <xsl:for-each select="$property/ancestor::adl:entity/adl:key/adl:property[position()=1]"> <xsl:variable name="keybasetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> matchCriteria.Add(Expression.Not(<xsl:call-template name="hibernate-expression-eq"> <xsl:with-param name="property" select="."/> <xsl:with-param name="value"> Form["<xsl:value-of select="concat( 'instance.', @name)"/>"] </xsl:with-param> </xsl:call-template>)); </xsl:for-each> } if ( matchCriteria.List<<xsl:value-of select="$property/ancestor::adl:entity/@name"/>>().Count > 0) { AddError( String.Format("There is already a {0} with the {1} '{2}'", "<xsl:value-of select="$property/ancestor::adl:entity/@name"/>", "<xsl:value-of select="$property/@name"/>", Form["<xsl:value-of select="concat('instance.', $property/@name)"/>"])); } </xsl:when> </xsl:choose> </xsl:template> <!-- produce all menus for a given form: harder, but more efficient --> <xsl:template name="formmenus"> <!-- an entity assumed to be of type adl:form --> <xsl:param name="form"/> <xsl:choose> <xsl:when test="$form/@properties = 'all'"> <xsl:call-template name="entitymenus"> <xsl:with-param name="entity" select="$form/ancestor::adl:entity"/> </xsl:call-template> </xsl:when> <xsl:otherwise> /* form menus */ <xsl:for-each select="$form//adl:field"> <xsl:variable name="propname" select="@property"/> <xsl:choose> <xsl:when test="parent::adl:auxlist"/> <xsl:when test="$form/ancestor::adl:entity/adl:property[@name=$propname and @type='entity']"> /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity/adl:property[@name=$propname]/@entity"/> to populate the select for <xsl:value-of select="$propname"/> */ <xsl:call-template name="menu"> <xsl:with-param name="property" select="$form/ancestor::adl:entity/adl:property[@name=$propname]"/> </xsl:call-template> </xsl:when> <xsl:when test="$form/ancestor::adl:entity/adl:property[@name=$propname and @type='link']"> /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity/adl:property[@name=$propname]/@entity"/> to populate the LHS of the shuffle for <xsl:value-of select="$propname"/> */ <xsl:call-template name="menu"> <xsl:with-param name="property" select="$form/ancestor::adl:entity/adl:property[@name=$propname]"/> </xsl:call-template> </xsl:when> <xsl:when test="$form/ancestor::adl:entity/adl:property[@name=$propname and @type='list']"> /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity/adl:property[@name=$propname]/@entity"/> to populate the multi-select for <xsl:value-of select="@name"/> */ <xsl:call-template name="menu"> <xsl:with-param name="property" select="$form/ancestor::adl:entity/adl:property[@name=$propname]"/> </xsl:call-template> </xsl:when> </xsl:choose> </xsl:for-each> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- produce all menus for a given entity: easier, but less efficient --> <xsl:template name="entitymenus"> <xsl:param name="entity"/> /* there's no way I can find of producing a set of just those entities * we'll need menus for. So we set up variables for all the menus we might * need, and then only instantiate those we do need. */ <!-- xsl:for-each select="//adl:entity"> IList<<xsl:value-of select="concat( $entityns, '.', @name)"/>> <xsl:value-of select="concat( 'all', @name)"/> = null; </xsl:for-each --> <xsl:for-each select="$entity//adl:property[@type='entity']"> <!-- $entity//adl:property because it is possible to have type='entity' in the key --> <xsl:call-template name="menu"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:for-each> <xsl:for-each select="$entity/adl:property[@type='link']"> <!-- $entity/adl:property because it is not possible to have type='link' in the key --> /* produce a list of <xsl:value-of select="@entity"/> to populate the LHS of the shuffle for <xsl:value-of select="@name"/> */ <xsl:call-template name="menu"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:for-each> <xsl:for-each select="$entity/adl:property[@type='list']"> /* produce a list of <xsl:value-of select="@entity"/> to populate the multi-select for <xsl:value-of select="@name"/> */ <xsl:call-template name="menu"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:for-each> </xsl:template> <xsl:template name="menu"> <xsl:param name="property"/> <xsl:variable name="entity" select="//adl:entity[@name=$property/@entity]"/> <xsl:value-of select="concat('all_', $property/@name)"/> = <xsl:value-of select="concat( 'FetchAll', $entity/@name)"/>( ), </xsl:template> <xsl:template name="primary-key-csharp-type"> <xsl:param name="entity"/> <xsl:if test="not( $entity)"> <xsl:message terminate="yes"> ADL: ERROR: No entity passed to template primary-key-csharp-type </xsl:message> </xsl:if> <xsl:if test="not($entity/adl:key/adl:property)"> <xsl:message terminate="no"> ADL: WARNING: entity '<xsl:value-of select="$entity/@name"/>' has no primary key. You will have to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> </xsl:message> </xsl:if> <xsl:call-template name="csharp-type"> <xsl:with-param name="property" select="$entity/adl:key/adl:property[ position() = 1]"/> <xsl:with-param name="entityns" select="$entityns"/> </xsl:call-template> </xsl:template> <xsl:template name="primary-key-name"> <!-- return the name of the primary key of the entity with this name --> <xsl:param name="entity"/> <xsl:if test="not($entity/adl:key)"> <xsl:message terminate="yes"> ADL: ERROR: No key for entity: <xsl:value-of select="$entity/@name"/> </xsl:message> </xsl:if> <xsl:choose> <xsl:when test="$entity/adl:key/adl:property[position()=2]"> <xsl:message terminate="no"> ADL: WARNING: Entity <xsl:value-of select="$entity/@name"/> has a composite primary key. You will need to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> </xsl:message> <xsl:value-of select="$entity/adl:key/adl:property[position()=1]/@name"/> </xsl:when> <xsl:when test="$entity/adl:key/adl:property"> <xsl:value-of select="$entity/adl:key/adl:property[position()=1]/@name"/> </xsl:when> <xsl:otherwise> <xsl:message terminate="no"> ADL: WARNING: Entity <xsl:value-of select="$entity/@name"/> has no primary key. You will need to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> </xsl:message> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- it's often convenient to wrap an expression in an Add() --> <xsl:template name="add-hibernate-expression-eq"> <xsl:param name="property"/> <xsl:param name="value"/> <xsl:variable name="basetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="$property"/> </xsl:call-template> </xsl:variable> .Add(<xsl:call-template name="hibernate-expression-eq"> <xsl:with-param name="property" select="$property"/> <xsl:with-param name="value" select="$value"/> </xsl:call-template>) </xsl:template> <!-- it's often convenient to wrap an expression in an Add() --> <xsl:template name="add-hibernate-expression-like"> <xsl:param name="property"/> <xsl:param name="value"/> <xsl:variable name="basetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="$property"/> </xsl:call-template> </xsl:variable> .Add(<xsl:call-template name="hibernate-expression-like"> <xsl:with-param name="property" select="$property"/> <xsl:with-param name="value" select="$value"/> </xsl:call-template>) </xsl:template> <!-- generate a hibernate equality expression based on this property, comparing it to this value --> <xsl:template name="hibernate-expression-eq"> <!-- an entity of type property --> <xsl:param name="property"/> <!-- an expression which, at run time, will evaluate to a string --> <xsl:param name="value"/> <xsl:variable name="basetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="$property"/> </xsl:call-template> </xsl:variable> Expression.Eq("<xsl:value-of select="$property/@name"/>", <xsl:choose> <xsl:when test="$basetype = 'string'"> <xsl:value-of select="$value"/> </xsl:when> <xsl:when test="$basetype = 'integer'"> Int32.Parse( <xsl:value-of select="$value"/>) </xsl:when> <xsl:when test="$basetype = 'money'"> Decimal.Parse( <xsl:value-of select="$value"/>) </xsl:when> <xsl:when test="$basetype = 'date'"> DateTime.Parse( <xsl:value-of select="$value"/>) </xsl:when> <xsl:when test="$basetype='entity'"> <xsl:call-template name="fetch-property-instance"> <xsl:with-param name="property" select="$property"/> <xsl:with-param name="value" select="$value"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:message terminate="yes"> ADL: Error: properties of type <xsl:value-of select="$basetype"/> cannot yet be used in equality tests </xsl:message> </xsl:otherwise> </xsl:choose>) </xsl:template> <!-- generate a hibernate like expression based on this property, comparing it to this value --> <xsl:template name="hibernate-expression-like"> <xsl:param name="property"/> <xsl:param name="value"/> <xsl:variable name="basetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="$property"/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$basetype='string' or $basetype='text'"> Expression.Like( "<xsl:value-of select="@name"/>", "%"+<xsl:value-of select="$value"/>+"%") </xsl:when> <xsl:when test="$basetype='real'"> /* match to four significant places */ Expression.Between( "<xsl:value-of select="@name"/>", Double.Parse( <xsl:value-of select="$value"/>) * 1.0001, Double.Parse( <xsl:value-of select="$value"/>) * 0.9999) </xsl:when> <xsl:otherwise> <xsl:call-template name="hibernate-expression-eq"> <xsl:with-param name="property" select="$property"/> <xsl:with-param name="value" select="$value"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- argument: a property returns 'true' if that property is of a type which makes it searchable, else 'false'. See also how search fields are generated in adl2views.xsl --> <xsl:template name="is-searchable"> <xsl:param name="property"/> <xsl:variable name="base-type"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="$property"/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$base-type='string'">true</xsl:when> <xsl:when test="$base-type='integer'">true</xsl:when> <xsl:when test="$base-type='real'">true</xsl:when> <xsl:when test="$base-type='money'">true</xsl:when> <xsl:when test="$base-type='text'">true</xsl:when> <xsl:when test="$base-type='entity'">true</xsl:when> <xsl:otherwise>false</xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="fetch-property-instance"> <!-- the property for which the instance is sought; it is assumed that the property passed has type 'entity' --> <xsl:param name="property"/> <!-- the name of the value in the returned values from which the instance must be resolved --> <xsl:param name="value"/> <xsl:variable name="basetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="$property"/> </xsl:call-template> </xsl:variable> <xsl:if test="not( $basetype='entity')"> <xsl:message terminate="yes"> ADL: ERROR: property passed to fetch-property-instance whose type is not 'entity' </xsl:message> </xsl:if> hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', $property/@entity)"/>)) <xsl:for-each select="//adl:entity[@name=$property/@entity]/adl:key/adl:property"> <xsl:call-template name="add-hibernate-expression-eq"> <xsl:with-param name="property" select="."/> <xsl:with-param name="value" select="$value"/> </xsl:call-template> </xsl:for-each> .UniqueResult<<xsl:value-of select="concat( $entityns, '.', $property/@entity)"/>>() </xsl:template> </xsl:stylesheet>