前两天用nhibernate的时候用户提交过来一个错误,说一个文本输入框输入字符过长,会被在固定的地方截断,经过试验发现4000个字符8000个字节的时候会被截断。
看了一下映射文件中的xml配置,发现映射字段如下:
<property column="InfoContent" type="String" name="InfoContent" length="2147483647" />
虽然该字段的长度被设置的足够大,但是使用过程中还是被截断了。
查看了一下nhibernate的源码,发现在实际操作过程中发现nhibernate对string的处理时候自动将string类型按照数据中的nvarchar类型处理,最大长度4000字符,超过后自动截掉。查看了一下nhibernate 1.02的接口类型发现有一个StringClob,是处理长字符串的。
改变了xml里面的类型设置后,测试通过。
<property column="InfoContent" type="StringClob" name="InfoContent" length="2147483647" />
和Nhibernate相关的配置一直都是用MyGeneration的Nhibernate Object Mapping 1.1的模板生成的,我对该模板进行了稍微的修改,判断了一下字段的长度,如果长度是Text或者NText的长度就将字段类型修改为“StringClob”,现在共享给大家,希望对大家有帮助。
修改后的模板:(由于这里不能上传附件,下载后保存到mygeneration的nhibernate目录下即可)
##|UNIQUEID 751f78af-5424-4d4e-8676-4712f98788e3
##|TITLE NHibernate Object Mapping 1.1.1
##|NAMESPACE NHibernate
##|OUTPUT_LANGUAGE C#
##|COMMENTS_BEGIN
This is an update of k-dub's NHibernate Object Mapping template. Generate C# classes or hbm mapping files or both. Can use tables or views. Can specify "read-only". Can generate overridden Equals and GetHashCode methods. Added support for one-to-many mappings.
##|COMMENTS_END
##|GUI_ENGINE .Net Script
##|GUI_LANGUAGE C#
##|GUI_BEGIN
<%#REFERENCE System.Windows.Forms.dll %>
<%#NAMESPACE System, System.Text, System.Collections, Zeus, Zeus.UserInterface, Zeus.DotNetScript %>
public class GeneratedGui : DotNetScriptGui
{
public GeneratedGui( ZeusGuiContext context ) : base( context ) {}
public override void Setup()
{
if ( !input.Contains( "chooseTables" ) || !input.Contains( "txtPath" ) ||
( !input.Contains( "chkClass" ) && !input.Contains( "chkNaming" ) ) )
{
ui.Title = "NHibernate Object Mapping";
ui.Width = 600;
ui.Height = 640;
// Grab default output path
string sOutputPath = "";
if( input.Contains( "defaultOutputPath" ) )
{
sOutputPath = input["defaultOutputPath"].ToString();
}
// Setup Folder selection input control.
GuiLabel label1 = ui.AddLabel( "label1", "Select the output path:", "Select the output path in the field below." );
label1.Width = 200;
GuiTextBox outputPath = ui.AddTextBox( "outputPath", sOutputPath, "Select the Output Path." );
outputPath.Width = 450;
GuiFilePicker selectPath = ui.AddFilePicker( "selectPath", "Select Path", "Select the Output Path.", "outputPath", true );
selectPath.Top = outputPath.Top;
selectPath.Width = 100;
selectPath.Left = outputPath.Left + outputPath.Width + 20;
GuiLabel label2 = ui.AddLabel( "label2", "Namespace: ", "Provide your objects namespace." );
label2.Width = 280;
GuiTextBox classNamespace = ui.AddTextBox( "classNamespace", "Business.Data", "Provide your objects namespace." );
classNamespace.Width = 280;
GuiLabel label3 = ui.AddLabel( "label3", "Member variable prefix: ", "Provide your Prefix." );
label3.Width = 280;
label3.Top = label2.Top;
label3.Left = label2.Width + 20;
GuiTextBox memberPrefix = ui.AddTextBox( "memberPrefix", "m_", "" );
memberPrefix.Width = 280;
memberPrefix.Top = classNamespace.Top;
memberPrefix.Left = classNamespace.Width + 20;
// Setup Database selection combobox.
GuiLabel label4 = ui.AddLabel( "label4", "Select a database:", "Select a database in the dropdown below." );
label4.Width = 250;
GuiComboBox chooseDatabase = ui.AddComboBox( "chooseDatabase", "Select a database." );
chooseDatabase.Width = 250;
GuiLabel label5 = ui.AddLabel( "label5", "Output type:", "Select one or both." );
label5.Width = 150;
label5.Top = label4.Top;
label5.Left = label4.Width + 20;
GuiCheckBox chkClass = ui.AddCheckBox( "chkClass", "Create class files.", true, "Create a class file for each table or view selected. (*.cs)" );
chkClass.Width = 150;
chkClass.Top = chooseDatabase.Top;
chkClass.Left = chooseDatabase.Width + 20;
GuiCheckBox chkMapping = ui.AddCheckBox( "chkMapping", "Create XML mapping files.", true, "Create an XML file for each table or view selected. (*.hbm.xml)" );
chkMapping.Width = 150;
chkMapping.Top = chkClass.Top + 20;
chkMapping.Left = chkClass.Left;
GuiLabel label6 = ui.AddLabel( "label6", "Read Only:", "Create as read only?" );
label6.Width = 150;
label6.Top = label5.Top;
label6.Left = label5.Left + label5.Width + 20;
GuiCheckBox chkReadOnly = ui.AddCheckBox( "chkReadOnly", "Create as read-only.", false, "Create object and mapping to have read-only access." );
chkReadOnly.Width = 150;
chkReadOnly.Top = chkClass.Top;
chkReadOnly.Left = chkClass.Left + chkClass.Width + 20;
GuiCheckBox chkDefaultEmptyConstructor = ui.AddCheckBox( "chkDefaultEmptyConstructor", "Create a default (empty) constructor. Required.", true, "Create a default constructor with empty fields." );
chkDefaultEmptyConstructor.Top = chkMapping.Top + 20;
GuiCheckBox chkRequiredFieldsConstructor = ui.AddCheckBox( "chkRequiredFieldsConstructor", "Create a constructor with all required (non-null) fields as parameters.", true, "Create a constructor with all required (non-null) fields as parameters" );
chkRequiredFieldsConstructor.Top = chkDefaultEmptyConstructor.Top + 20;
GuiCheckBox chkIncludePKInReqFieldsCtorArgs = ui.AddCheckBox( "chkIncludePKInReqFieldsCtorArgs", "Include primary key in required fields constructor.", false, "Include primary key in the parameter list for the required fields constructor." );
chkIncludePKInReqFieldsCtorArgs.Top = chkRequiredFieldsConstructor.Top + 20;
GuiCheckBox chkEqualsHashCode = ui.AddCheckBox( "chkEqualsHashCode", "Create Equals and GetHashCode.", false, "Generate Equals and GetHashCode methods." );
chkEqualsHashCode.Top = chkIncludePKInReqFieldsCtorArgs.Top + 20;
// Setup Tables selection multi-select listbox.
GuiLabel label7 = ui.AddLabel( "label7", "Select tables:", "Select tables from the listbox below." );
label7.Top = chkEqualsHashCode.Top + 20;
GuiListBox chooseTables = ui.AddListBox( "chooseTables", "Select tables." );
chooseTables.Height = 120;
// Setup Views selection multi-select listbox.
GuiLabel label8 = ui.AddLabel( "label8", "Select views:", "Select views from the listbox below." );
GuiListBox chooseViews = ui.AddListBox( "chooseViews", "Select views." );
chooseViews.Height = 120;
// Attach the onchange event to the cmbDatabases control.
setupDatabaseDropdown( chooseDatabase );
chooseDatabase.AttachEvent( "onchange", "chooseDatabase_onchange" );
ui.ShowGui = true;
}
else
{
ui.ShowGui = false;
}
}
public void setupDatabaseDropdown( GuiComboBox Databases )
{
try
{
if( MyMeta.IsConnected )
{
Databases.BindData( MyMeta.Databases );
if( MyMeta.DefaultDatabase != null )
{
Databases.SelectedValue = MyMeta.DefaultDatabase.Alias;
bindTables( Databases.SelectedValue );
bindViews( Databases.SelectedValue );
}
}
}
catch
{
}
}
public void bindTables( string sDatabase )
{
int count = 0;
GuiListBox lstTables = ui["chooseTables"] as GuiListBox;
try
{
IDatabase db = MyMeta.Databases[sDatabase];
lstTables.BindData( db.Tables );
}
catch
{
}
}
public void bindViews( string sDatabase )
{
int count = 0;
GuiListBox lstViews = ui["chooseViews"] as GuiListBox;
try
{
IDatabase db = MyMeta.Databases[sDatabase];
lstViews.BindData( db.Views );
}
catch
{
}
}
public void chooseDatabase_onchange( GuiComboBox control )
{
int count = 0;
GuiComboBox cmbDatabases = ui["chooseDatabase"] as GuiComboBox;
bindTables( cmbDatabases.SelectedText );
bindViews( cmbDatabases.SelectedText );
}
}
##|GUI_END
##|BODY_MODE Markup
##|BODY_ENGINE .Net Script
##|BODY_LANGUAGE C#
##|BODY_TAG_START <%
##|BODY_TAG_END %>
##|BODY_BEGIN
<%#NAMESPACE System.IO, System.Text, System.Text.RegularExpressions, System.Globalization %><%
public class GeneratedTemplate : DotNetScriptTemplate
{
private ArrayList _selectedTables;
private ArrayList _selectedViews;
private string _dbName;
private string _tableName;
private string _className;
private string _exportPath;
private string _fileName;
private string _nameSpace;
private string _prefix;
private bool _createClassFiles;
private bool _createXmlFiles;
private bool _createReadOnly;
private bool _generateEqualsHashCode;
private bool _generateDefaultCtor;
private bool _generateRequiredFieldsCtor;
private bool _includePKInReqFieldsCtorArgs;
public GeneratedTemplate( ZeusContext context ) : base( context ) {}
public override void Render()
{
_dbName = input["chooseDatabase"].ToString();
_selectedTables = input["chooseTables"] as ArrayList;
_selectedViews = input["chooseViews"] as ArrayList;
_exportPath = input["outputPath"].ToString();
_nameSpace = input["classNamespace"].ToString();
_prefix = input["memberPrefix"].ToString();
_createClassFiles = (bool)input["chkClass"];
_createXmlFiles = (bool)input["chkMapping"];
_createReadOnly = (bool)input["chkReadOnly"];
_generateEqualsHashCode = (bool)input["chkEqualsHashCode"];
_generateDefaultCtor = (bool) input["chkDefaultEmptyConstructor"];
_generateRequiredFieldsCtor = (bool) input["chkRequiredFieldsConstructor"];
_includePKInReqFieldsCtorArgs = (bool) input["chkIncludePKInReqFieldsCtorArgs"];
foreach( string _newTable in _selectedTables )
{
ITable _workingTable = MyMeta.Databases[_dbName].Tables[_newTable];
_tableName = _workingTable.Alias.Replace( " ", "" );
_className = ToPascalCase( _tableName );
if( _createClassFiles )
{
GenerateClassFile( _workingTable.Columns );
}
if( _createXmlFiles )
{
GenerateMappingFile( _workingTable.Columns );
}
}
foreach( string _newView in _selectedViews )
{
IView _workingView = MyMeta.Databases[_dbName].Views[_newView];
_tableName = _workingView.Alias.Replace( " ", "" );
_className = ToPascalCase( _tableName );
if( _createClassFiles )
{
GenerateClassFile( _workingView.Columns );
}
if( _createXmlFiles )
{
GenerateMappingFile( _workingView.Columns );
}
}
}
private void GenerateClassFile( IColumns Columns )
{
output.writeln( "/*" );
output.writeln( "insert license info here" );
output.writeln( "*/" );
output.writeln( "using System;" );
output.writeln( "using System.Collections;" );
output.writeln( "" );
output.write( "namespace " );
output.writeln( _nameSpace );
output.writeln( "{" );
output.writeln( "/t/// <summary>" );
output.writeln( "/ttGenerated by MyGeneration using the NHibernate Object Mapping template" );
output.writeln( "/t/// </summary>" );
output.writeln( "/t[Serializable]" );
output.write( "/tpublic sealed class " );
output.writeln( _className );
output.writeln( "/t{" );
BuildPrivateMembers( Columns );
if( _generateDefaultCtor )
BuildDefaultConstructor( Columns );
if( _generateRequiredFieldsCtor )
BuildRequiredFieldsCtor( Columns );
BuildPublicAccessors( Columns );
// BuildPublicFunctions( Columns );
if( _generateEqualsHashCode )
BuildEqualsHashCodeOverrides( Columns );
output.writeln( "/t}" );
output.writeln( "}" );
_fileName = _className + ".cs";
output.save( Path.Combine( _exportPath, _fileName ), false );
output.clear();
}
private void GenerateMappingFile( IColumns Columns )
{
BuildHBMDefinition( Columns );
_fileName = _className + ".hbm.xml";
output.save( Path.Combine( _exportPath, _fileName ), false );
output.clear();
}
private void BuildDefaultConstructor( IColumns Columns )
{
%>
#region Default ( Empty ) Class Constuctor
/// <summary>
/// default constructor
/// </summary>
public <%= _className %>()
{<%
foreach( IColumn field in Columns )
{
string fieldName = ColumnToMemberVariable( field );
string fieldType = ( field.IsInForeignKey && !field.IsInPrimaryKey ? ColumnFKToClassName( field) : ColumnToNHibernateType( field ) );
if( fieldType.EndsWith( "[]" ) )
{%>
<%= fieldName %> = new <%= fieldType %>{}; <%
}
else
{
switch( fieldType )
{
case "string":%>
<%= fieldName %> = String.Empty; <%
break;
case "DateTime":%>
<%= fieldName %> = DateTime.MinValue; <%
break;
case "bool":%>
<%= fieldName %> = false; <%
break;
case "decimal":
case "float":
case "short":
case "int":
case "long":%>
<%= fieldName %> = 0; <%
break;
default:%>
<%= fieldName %> = new <%= fieldType %>(); <%
break;
}
}
if( field.IsInForeignKey && field.IsInPrimaryKey )
{
//Here, there are foreign key relationships to this column,
//so there are collections in this class that represent those relationships.
//Initialize them.
foreach( IForeignKey fk in field.ForeignKeys )
{
output.writeln("");
output.write("/t/t/t");
output.write( _prefix );
output.write( ToPascalCase( fk.ForeignTable.Alias.Replace( " ", "" ) ) );
output.write( "List = new ArrayList(); " );
}
}
}
output.writeln( "" );
output.writeln( "/t/t}" );
output.writeln( "/t/t#endregion // End of Default ( Empty ) Class Constuctor" );
}
private void BuildRequiredFieldsCtor( IColumns Columns )
{
//If there are no required fields, don't make a ctor.
//Doing so will give a compiler error, since the result will
//have the same signature as the default ctor.
if( CountRequiredFields( Columns ) == 0 )
return;
output.writeln( "" );
output.writeln( "/t/t#region Required Fields Only Constructor" );
output.writeln( "/t/t/// <summary>" );
output.writeln( "/t/t/// required (not null) fields only constructor" );
output.writeln( "/t/t/// </summary>" );
output.write( "/t/tpublic " );
output.write( _className );
output.writeln( "(" );
bool first = true;
foreach( IColumn col in Columns )
{
if( !col.IsNullable && ( !col.IsInPrimaryKey || _includePKInReqFieldsCtorArgs ) )
{
if( !first )
{
output.writeln( ", " );
}
output.write( "/t/t/t" );
if( col.IsInForeignKey && !col.IsInPrimaryKey )
output.write( ColumnFKToClassName( col ) );
else
output.write( ColumnToNHibernateType( col ) );
output.write( " " + ColumnToArgumentName( col ) );
first = false;
}
}
output.writeln( ")" );
output.writeln( "/t/t/t: this()" );
output.writeln( "/t/t{" );
foreach( IColumn col in Columns )
{
if( col.IsInPrimaryKey && !_includePKInReqFieldsCtorArgs )
{
//Skip the primary key field, if instructed to do so.
continue;
}
output.write( "/t/t/t" );
if( !col.IsNullable && ( !col.IsInPrimaryKey || _includePKInReqFieldsCtorArgs ) )
{
output.write( ColumnToMemberVariable( col ) );
output.write( " = " );
output.write( ColumnToArgumentName( col ) );
output.writeln( ";" );
}
else
{
string fieldType = ( col.IsInForeignKey && !col.IsInPrimaryKey
? ColumnFKToClassName( col )
: ColumnToNHibernateType( col ) );
switch( fieldType )
{
default:
output.write( ColumnToMemberVariable( col ) );
output.writeln( " = null;" );
break;
case "string":
output.write( ColumnToMemberVariable( col ) );
output.writeln( " = String.Empty;" );
break;
case "DateTime":
output.write( ColumnToMemberVariable( col ) );
output.writeln( " = DateTime.MinValue;" );
break;
case "bool":
output.write( ColumnToMemberVariable( col ) );
output.writeln( " = false;" );
break;
case "decimal":
case "float":
case "short":
case "int":
case "long":
output.write( ColumnToMemberVariable( col ) );
output.writeln( " = 0;" );
break;
}
}
}
output.writeln( "/t/t}" );
output.writeln( "/t/t#endregion // End Required Fields Only Constructor" );
}
private void BuildFullConstructor( IColumns Columns )
{
%>#region Full Constructor
/// <summary>
/// full constructor
/// </summary>
public <%= _className %>(<%
bool first = true;
foreach( IColumn field in Columns )
{
if( !first ) output.write( ", " );
output.write( ( field.IsInForeignKey && !field.IsInPrimaryKey ? ToPascalCase( field.ForeignKeys[0].PrimaryTable.Alias.Replace( " ", "" ) ) : ColumnToNHibernateType( field ) ) + " " + ColumnToArgumentName( field ) );
first = false;
}%>)
{<%
foreach( IColumn col in Columns )
{
%>
<%= ColumnToMemberVariable( col ) %> = <%= ColumnToArgumentName( col ) %>; <%
}
%>
}
#endregion // End Full Constructor<%
}
private void BuildEqualsHashCodeOverrides( IColumns Columns )
{
%>
#region Equals And HashCode Overrides
/// <summary>
/// local implementation of Equals based on unique value members
/// </summary>
public override bool Equals( object obj )
{
if( this == obj ) return true;
if( ( obj == null ) || ( obj.GetType() != this.GetType() ) ) return false;
<%= _className %> castObj = (<%= _className %>)obj; <%
if( CountUniqueFields( Columns ) == 0 )
{%>
return castObj.GetHashCode() == this.GetHashCode()<%
}
else
{%>
return ( castObj != null )<%
foreach( IColumn c in Columns )
{
if( c.IsInPrimaryKey )
{
%> &&
( this.<%= ColumnToMemberVariable( c ) %> == castObj.<%= ColumnToPropertyName( c ) %> )<%
}
}
} %>;
}
/// <summary>
/// local implementation of GetHashCode based on unique value members
/// </summary>
public override int GetHashCode()
{
<% if( CountUniqueFields( Columns ) == 0 )
{
%>return this.GetType().FullName.GetHashCode();
<%
}
else
{%>
int hash = 57; <%
foreach( IColumn c in Columns )
{
if( c.IsInPrimaryKey )
{
%>
hash = 27 * hash * <%= ColumnToMemberVariable( c ) %>.GetHashCode();<%
}
}
%>
return hash; <%
}%>
}
#endregion
<%
}
private void BuildPrivateMembers( IColumns Columns )
{
if( Columns.Count > 0 )
{
%>
#region Private Members
private bool <%= _prefix %>isChanged;
<%
foreach( IColumn field in Columns )
{
if( field.IsInForeignKey )
{
if ( !field.IsInPrimaryKey )
{
// A column that's in a fk but not in the pk is an actual foreign key,
// a many-to-one relationship. So the member variable is a class instance.
%>
private <%= ToPascalCase( field.ForeignKeys[0].PrimaryTable.Alias.Replace( " ", "" ) ) %> <%= ColumnToMemberVariable( field ) %>; <%
}
else
{
//A column that's in a fk and in the pk represents a fk relationship
//from another table, a one-to-many relationship. (This might be
//a bad assumption for a table with a composite primary key.)
//So we have to add the pk member variable itself...
%>
private <%= ColumnToNHibernateType( field ) %> <%= ColumnToMemberVariable( field ) %>; <%
//... and then we have to add collections for the foreign tables.
foreach( IForeignKey fk in field.ForeignKeys )
{
output.writeln("");
output.write( "/t/tprivate IList " );
output.write( _prefix );
output.write( ToPascalCase( fk.ForeignTable.Alias.Replace( " ", "" ) ) );
output.write( "List; " );
}
}
}
else
{%>
private <%= ColumnToNHibernateType( field ) %> <%= ColumnToMemberVariable( field ) %>; <%
}
}
%>
#endregion
<%
}
}
private void BuildInternalAccessors( IColumns Columns )
{
if( Columns.Count > 0 )
{
%>#region Internal Accessors for NHibernate
<%
foreach( IColumn field in Columns )
{
string fieldAccessor = ColumnToNHibernateProperty( field );
string fieldName = ColumnToMemberVariable( field );
%>
#region <%= fieldAccessor %>
/// <summary>
/// <%= field.Description %>
/// </summary>
internal <%= ColumnToNHibernateType( field ) %> <%= fieldAccessor %>
{
get { return <%= fieldName %>; }
set { <%= fieldName %> = value; }
}
#endregion
<%
}
%>
#endregion // Internal Accessors for NHibernate <%
}
}
private void BuildPublicAccessors( IColumns Columns )
{
if( Columns.Count > 0 )
{
%>
#region Public Properties
<%
foreach( IColumn field in Columns )
{
string fieldAccessor = ColumnToPropertyName( field );
string fieldName = ColumnToMemberVariable( field );
string fieldType = ( field.IsInForeignKey && !field.IsInPrimaryKey ? ToPascalCase( field.ForeignKeys[0].PrimaryTable.Alias.Replace( " ", "" ) ) : ColumnToNHibernateType( field ) );
output.writeln( "" );
output.writeln( "/t/t/// <summary>" );
foreach( string s in field.Description.Split( new char[] { '/n' } ) )
{
output.writeln( "/t/t/// " + s );
}
output.writeln( "/t/t/// </summary>" );
output.writeln( "/t/tpublic " + fieldType + " " + fieldAccessor );
output.writeln( "/t/t{" );
output.writeln( "/t/t/tget { return " + fieldName + "; }" );
if( !_createReadOnly )
{
//if(!((field.IsInPrimaryKey && field.IsAutoKey) || field.IsComputed))
//{
switch( fieldType )
{
default:
output.writeln( "/t/t/tset" );
output.writeln( "/t/t/t{" );
if( !field.IsNullable && !IsValueType( fieldType ) )
{
output.writeln( "/t/t/t/tif( value == null )" );
output.writeln( "/t/t/t/t/tthrow new ArgumentOutOfRangeException(/"Null value not allowed for " + fieldAccessor + "/", value, /"null/");" );
output.writeln( "" );
}
output.write( "/t/t/t/t" );
output.write( _prefix );
output.write( "isChanged |= ( " );
output.write( fieldName );
output.writeln( " != value ); " );
output.write( "/t/t/t/t" );
output.write( fieldName );
output.writeln( " = value;" );
output.writeln( "/t/t/t}" );
break;
case "byte": %>
set
{ <%if( !field.IsNullable )
{%>
if( value == null )
throw new ArgumentOutOfRangeException("Null value not allowed for <%= fieldAccessor %>", value, "null");
<%}%>
if( <%if( field.IsNullable ) {%> value != null && <%}%> value.Length > <%= field.CharacterMaxLength.ToString() %>)
throw new ArgumentOutOfRangeException("Invalid value for <%= fieldAccessor %>", value, value.ToString());
<%= _prefix %>isChanged |= (<%= fieldName %> != value); <%= fieldName %> = value;
}
<%
break;
case "string": %>
set
{ <%if( !field.IsNullable )
{%>
if( value == null )
throw new ArgumentOutOfRangeException("Null value not allowed for <%= fieldAccessor %>", value, "null");
<%}%>
if( <%if( field.IsNullable ) {%> value != null && <%}%> value.Length > <%= field.CharacterMaxLength.ToString() %>)
throw new ArgumentOutOfRangeException("Invalid value for <%= fieldAccessor %>", value, value.ToString());
<%= _prefix %>isChanged |= (<%= fieldName %> != value); <%= fieldName %> = value;
}<%
break;
}
//}
}%>
}
<%
if( field.IsInForeignKey && field.IsInPrimaryKey )
{
//This means that there are collections implementing
//one-to-many relationships based on this column. So
//we need accessors for those collections, too.
foreach( IForeignKey fk in field.ForeignKeys )
{
output.writeln("");
output.write( "/t/tpublic IList " );
output.write( ToPascalCase( fk.ForeignTable.Alias.Replace( " ", "" ) ) );
output.writeln( "List" );
output.writeln( "/t/t{" );
output.writeln( "/t/t/tget" );
output.writeln( "/t/t/t{" );
output.write( "/t/t/t/treturn " );
output.write( _prefix );
output.write( ToPascalCase( fk.ForeignTable.Alias.Replace( " ", "" ) ) );
output.writeln( "List;" );
output.writeln( "/t/t/t}" );
output.writeln( "/t/t/tset" );
output.writeln( "/t/t/t{" );
output.write( "/t/t/t/t" );
output.write( _prefix );
output.write( ToPascalCase( fk.ForeignTable.Alias.Replace( " ", "" ) ) );
output.writeln( "List = value;" );
output.writeln( "/t/t/t}" );
output.writeln( "/t/t}" );
}
}
}
%>
/// <summary>
/// Returns whether or not the object has changed it's values.
/// </summary>
public bool IsChanged
{
get { return <%= _prefix %>isChanged; }
}
#endregion
<%
}
}
private void BuildPublicFunctions( IColumns Columns )
{%>
#region Public Functions
/// <summary>
/// mark the item as deleted
/// </summary>
public void MarkAsDeleted()
{
<%= _prefix %>isDeleted = true;
<%= _prefix %>isChanged = true;
}
#endregion<%
}
private void BuildHBMDefinition( IColumns Columns )
{
if( Columns.Count > 0 )
{
output.writeln( "<?xml version=/"1.0/" encoding=/"utf-8/" ?>" );
output.writeln( NHibernateMappingTag() );
output.writeln( "/t" + NHibernateClassTag( Columns ) );
output.writeln( "/t/t" + NHibernatePrimaryKeysTag( Columns ) );
output.writeln( "/t/t" + NHibernateProperties( Columns ) );
output.writeln( "/t</class>" );
output.writeln( "</hibernate-mapping>" );
}
}
private string NHibernateMappingTag()
{
can't handle external mappings ?!?
string xml = "<hibernate-mapping xmlns=/"http://nhibernate.sourceforge.net/schemas/nhibernate-mapping-2.0.xsd/"";
//string xml = "<hibernate-mapping xmlns=/"urn:nhibernate-mapping-2.0/"";
handle schemas, cascade, import, and access methods?
//return xml + ">";
return "<hibernate-mapping xmlns=/"urn:nhibernate-mapping-2.0/">";
}
private string NHibernateClassTag( IColumns Columns )
{
//ITable t = Columns[0].Table;
//IView v = Columns[0].View;
//string desc = ( t == null ) ? v.Description : t.Description;
StringBuilder xml = new StringBuilder();
xml.Append( "<class name=/"" ).Append( _nameSpace ).Append( "." ).Append( _className ).Append( "," ).Append( _nameSpace ).Append( "/"" );
xml.Append( " table=/"" ).Append( _tableName ).Append( "/"" );
if( _createReadOnly )
{
xml.Append( " mutable=/"false/"" );
}
// handle schema override, dynamic insert & update, and proxies?
xml.Append( ">/r/n" );
return xml.ToString();
}
private string NHibernatePrimaryKeysTag( IColumns Columns )
{
StringBuilder xml = new StringBuilder();
int i = 0;
foreach( IColumn c in Columns )
{
if( c.IsInPrimaryKey )
{
i++;
}
}
if( i == 0 )
{
return "<!-- could not find a primary key for this table/view. NHibernate requires an 'id' element, so you'll have to define one manually. -->";
}
if( i == 1 )
{
foreach( IColumn c in Columns )
{
if( c.IsInPrimaryKey )
{
xml.Append( "<id name=/"" ).Append( ColumnToPropertyName( c ) ).Append( "/" column=/"" );
xml.Append( c.Alias ).Append( "/" type=/"" ).Append( ConvertNHibernate( ColumnToNHibernateType( c ) ) ).Append( "/"" );
switch( ColumnToNHibernateType( c ) )
{
case "decimal":
case "float":
case "short":
case "int":
case "long":
xml.Append( " unsaved-value=/"0/">/r/n" );
break;
default:
xml.Append( ">/r/n" );
break;
}
xml.Append( "/t/t/t<generator class=/"" );
xml.Append( ( c.IsAutoKey ) ? "native" : "assigned" );
xml.Append( "/"/>/r/n/t/t</id>" );
}
}
}
if( i > 1 )
{
xml.Append( "<!-- composite primary key support is touchy. View the documentation for syntax. -->" );
}
return xml.ToString();
}
private string NHibernateProperties( IColumns Columns )
{
StringBuilder xml = new StringBuilder();
foreach( IColumn c in Columns )
{
if( !c.IsInPrimaryKey )
{
// create sets & such for foreign keys !!!
if( c.IsInForeignKey )
{
if( c.ForeignKeys.Count > 1 )
{
xml.Append( "<!-- more than one foreign column is mapped to " ).Append( c.Name ).Append( " - you're on your own. -->/r/n/t/t" );
}
else
{
IForeignKey fk = c.ForeignKeys[0];
xml.Append( "<many-to-one name=/"" )
.Append( ColumnToPropertyName( c ) )
.Append( "/" column=/"" )
.Append( c.Name );
xml.Append( "/" class=/"" )
.Append( _nameSpace )
.Append( "." )
.Append( ToPascalCase( fk.PrimaryTable.Alias.Replace( " ", "" ) ) )
.Append( "," )
.Append( _nameSpace )
.Append( "/" />/r/n/t/t" );
}
}
else
{
xml.Append( "<property column=/"" ).Append( c.Name );
//20061204 增加的支持text、ntext类型的字段
if(ColumnToNHibernateType( c ) == "string" && (c.CharacterMaxLength == 1073741823 || c.CharacterMaxLength == 2147483647))
xml.Append( "/" type=/"" ).Append( "StringClob" ).Append( "/"" );
else
xml.Append( "/" type=/"" ).Append( ConvertNHibernate( ColumnToNHibernateType( c ) ) ).Append( "/"" );
if( _createReadOnly )
{
xml.Append( " access=/"field/" name=/"" ).Append( ColumnToMemberVariable( c ) ).Append( "/"" );
}
else
{
xml.Append( " name=/"" ).Append( ColumnToPropertyName( c ) ).Append( "/"" );
}
if( !c.IsNullable )
{
xml.Append( " not-null=/"true/"" );
}
if( c.LanguageType == "string" )
{
xml.Append( " length=/"" ).Append( c.CharacterMaxLength ).Append( "/"" );
}
xml.Append( " />/r/n/t/t" );
}
}
else
{ // c.IsInPrimaryKey is true here
if( c.IsInForeignKey )
{
//Here's where we handle one-to-many relations. A column that is in the PK, and is involved in FK relatioships,
//means it's the one in the one-to-many.
foreach( IForeignKey fk in c.ForeignKeys )
{
//Use a bag, since we don't know the real relationship.
xml.Append( "<bag ");
//The name for the collection property in the class.
//Made from the class name of the "many" side of the
//relationship, with "List" appended.
xml.Append( "name=/"" )
.Append( ToPascalCase( fk.ForeignTable.Alias.Replace( " ", "" ) ) )
.Append( "List/" " );
//This means that persisting the class object that contains this
//collection will not cause the collection's elements to be persisted.
//You have to navigate the collection and persist them individually.
xml.Append( "inverse=/"true/" " );
//Lazy loading. The collection is not filled until the application needs it.
xml.Append( "lazy=/"true/" " )
.Append( ">/r/n" );
//The key element specifies the column in the owning class/table that is the
//foreign key for the collection's class/table. Note this code only supports
//single-column foreign keys.
if( fk.ForeignColumns.Count > 1 )
{
xml.Append( "<!-- Composite foreign keys are not supported in this template. -->/r/n" );
}
else
{
xml.Append( "/t/t/t<key column=/"" )
.Append( fk.ForeignColumns[0].Name )
.Append( "/" />/r/n" );
}
//the one-to-many tag specifies the class of the objects in the
//collection, the "many" side.
xml.Append( "/t/t/t<one-to-many class=/"" )
.Append( _nameSpace )
.Append( "." )
.Append( ToPascalCase( fk.ForeignTable.Alias.Replace( " ", "" ) ) )
.Append( "," )
.Append( _nameSpace )
.Append( "/" />/r/n" );
//Close the bag tag and indent for the next column.
xml.Append( "/t/t</bag>/r/n/t/t" );
}
}
}
}
return xml.ToString();
}
private string ConvertNHibernate( string Type )
{
string retVal = Type;
switch( Type )
{
case "bool":
retVal = "Boolean";
break;
case "byte":
retVal = "Byte";
break;
case "sbyte":
retVal = "SByte";
break;
case "char":
retVal = "Char";
break;
case "decimal":
retVal = "Decimal";
break;
case "double":
retVal = "Double";
break;
case "float":
retVal = "Single";
break;
case "int":
retVal = "Int32";
break;
case "uint":
retVal = "UInt32";
break;
case "long":
retVal = "Int64";
break;
case "ulong":
retVal = "UInt64";
break;
case "short":
retVal = "Int16";
break;
case "ushort":
retVal = "UInt16";
break;
case "text":
retVal = "StringClob";
break;
case "string":
retVal = "String";
break;
}
return retVal;
}
private string ColumnToMemberVariable( IColumn Column )
{
return _prefix + UniqueColumn( Column ).ToLower();
}
private string ColumnToPropertyName( IColumn Column )
{
return ToPascalCase( UniqueColumn( Column ) );
}
private string ColumnFKToClassName( IColumn c )
{
return ToPascalCase( c.ForeignKeys[0].PrimaryTable.Alias.Replace( " ", "" ) );
}
private string ColumnToArgumentName( IColumn Column )
{
return UniqueColumn( Column ).ToLower();
}
private string ColumnToNHibernateProperty( IColumn Column )
{
return _prefix + UniqueColumn( Column );
}
private string UniqueColumn( IColumn Column )
{
string c = Column.Alias.Replace( " ", "" );
if( Column.Table != null && Column.Table.Alias.Replace( " ", "" ) == c )
{
c += "Name";
}
if( Column.View != null && Column.View.Alias.Replace( " ", "" ) == c )
{
c += "Name";
}
return c;
}
// nhibernate doesn't have these, so use the existing types
private string ColumnToNHibernateType( IColumn Column )
{
string retVal = Column.LanguageType;
switch( Column.LanguageType )
{
case "sbyte":
retVal = "byte";
break;
case "uint":
retVal = "int";
break;
case "ulong":
retVal = "long";
break;
case "ushort":
retVal = "short";
break;
}
return retVal;
}
private bool IsValueType( string type )
{
switch( type )
{
case "sbyte":
case "byte":
case "short":
case "ushort":
case "int":
case "uint":
case "long":
case "ulong":
case "char":
case "float":
case "double":
case "bool":
case "decimal":
case "DateTime":
return true;
break;
default:
return false;
break;
}
}
private string ToLeadingCaps( string name )
{
char[] chars = name.ToLower().ToCharArray();
chars[0] = Char.ToUpper( chars[0] );
return new string( chars );
}
private string ToLeadingLower( string name )
{
char[] chars = name.ToCharArray();
chars[0] = Char.ToLower( chars[0] );
return new string( chars );
}
private string ToPascalCase( string name )
{
string notStartingAlpha = Regex.Replace( name, "^[^a-zA-Z]+", "" );
string workingString = ToLowerExceptCamelCase( notStartingAlpha );
workingString = RemoveSeparatorAndCapNext( workingString );
return workingString;
}
private string RemoveSeparatorAndCapNext( string input )
{
string dashUnderscore = "-_";
string workingString = input;
char[] chars = workingString.ToCharArray();
int under = workingString.IndexOfAny( dashUnderscore.ToCharArray() );
while( under > -1 )
{
chars[ under + 1 ] = Char.ToUpper( chars[ under + 1 ], CultureInfo.InvariantCulture );
workingString = new String( chars );
under = workingString.IndexOfAny( dashUnderscore.ToCharArray(), under + 1 );
}
chars[ 0 ] = Char.ToUpper( chars[ 0 ], CultureInfo.InvariantCulture );
workingString = new string( chars );
return Regex.Replace( workingString, "[-_]", "" );
}
private string ToLowerExceptCamelCase( string input )
{
char[] chars = input.ToCharArray();
for( int i = 0; i < chars.Length; i++ )
{
int left = ( i > 0 ? i - 1 : i );
int right = ( i < chars.Length - 1 ? i + 1 : i );
if( i != left && i != right )
{
if( Char.IsUpper( chars[i] ) && Char.IsLetter( chars[ left ] ) && Char.IsUpper( chars[ left ] ) )
{
chars[i] = Char.ToLower( chars[i], CultureInfo.InvariantCulture );
}
else if( Char.IsUpper( chars[i] ) && Char.IsLetter( chars[ right ] ) && Char.IsUpper( chars[ right ] ) )
{
chars[i] = Char.ToLower( chars[i], CultureInfo.InvariantCulture );
}
else if( Char.IsUpper( chars[i] ) && !Char.IsLetter( chars[ right ] ) )
{
chars[i] = Char.ToLower( chars[i], CultureInfo.InvariantCulture );
}
}
}
chars[ chars.Length - 1 ] = Char.ToLower( chars[ chars.Length - 1 ], CultureInfo.InvariantCulture );
return new string( chars );
}
private int CountRequiredFields( IColumns Columns )
{
return Columns.Count - CountNullableFields( Columns );
}
private int CountNullableFields( IColumns Columns )
{
int i = 0;
foreach( IColumn c in Columns )
{
if( c.IsNullable )
{
i++;
}
}
return i;
}
private int CountUniqueFields( IColumns Columns )
{
int i = 0;
foreach( IColumn c in Columns )
{
if( !c.IsNullable && c.IsInPrimaryKey )
{
i++;
}
}
return i;
}
}
%>
##|BODY_END