用我的MyGeneration模板生成NHibernate映射文件和关系(one-to-one,one-to-many,many-to-many)
MyGeneration的几个NHibernate模板功能已经很强,但还是存在些问题。例如:Guid主键支持不佳,代码不易修改,不支持中文注释等等。所以我决定自己来改写此模版。我把一部分通用的函数提取到自己定义的基类中,这样调试和修改都方便另外增加了一部分新功能。
NHibernate里面的关系写起来也很烦人,很容易出错,所以我写了另一个模版专门生成关系代码。只需要把生成的代码拷到映射类文件和.hbm.xml文件中就可以了。
下载
如果你兴趣自己写模版,或者使用中有问题可以查看强大的代码生成工具MyGeneration 。
使用中发现什么问题,或者是有什么好的意见建议请及时和我联系。十分感谢!
下载完成后把DDLLY.MyGenerationTemplate.dll拷贝到MyGeneration的安装路径。把模版文件拷贝到MyGeneration的安装路径下的Templates目录里面的NHibernate目录里。
生成映射文件
运行MyGeneration,选择Edit里面的Default Settings...,进行适当的配置。如图
在Template Browser里面的NHibernate找到"DDL NHibernate Object Mapping"。运行此模版
输出路径表示生成模版的生成路径。启用nullable类型表示在.Net2.0中使用nullable类型,如果。
提示:你可以按住Ctrl或者Shift选择多个表。
Save按钮可以把的你设置存储在注册表中,下次将自动获得保存的设置。
选中你需要生成映射类的表,点Ok按钮。将生成映射文件。你可以在输出路径中找到他们。
下面是我生成的文件
/**/
/*
/*NHibernate映射代码模板
/*作者:DDL
/*版本更新和支持:http://renrenqq.cnblogs.com/
/*日期:2006年8月14日
*/
using
System;
namespace
MyNamePlace
{
/**//// <summary>
///
/// </summary>
[Serializable]
public sealed class User
{
私有成员#region 私有成员
private bool m_IsChanged;
private bool m_IsDeleted;
private int m_UserId;
private string m_UserName;
private string m_Password;
private string m_Email;
#endregion
默认( 空 ) 构造函数#region 默认( 空 ) 构造函数
/**//// <summary>
/// 默认构造函数
/// </summary>
public User()
{
m_UserId = 0;
m_UserName = null;
m_Password = null;
m_Email = null;
}
#endregion
公有属性#region 公有属性
/**//// <summary>
///
/// </summary>
public int UserId
{
get { return m_UserId; }
set { m_IsChanged |= (m_UserId != value); m_UserId = value; }
}
/**//// <summary>
///
/// </summary>
public string UserName
{
get { return m_UserName; }
set
{
if ( value != null)
if( value.Length > 64)
throw new ArgumentOutOfRangeException("Invalid value for UserName", value, value.ToString());
m_IsChanged |= (m_UserName != value); m_UserName = value;
}
}
/**//// <summary>
///
/// </summary>
public string Password
{
get { return m_Password; }
set
{
if ( value != null)
if( value.Length > 32)
throw new ArgumentOutOfRangeException("Invalid value for Password", value, value.ToString());
m_IsChanged |= (m_Password != value); m_Password = value;
}
}
/**//// <summary>
///
/// </summary>
public string Email
{
get { return m_Email; }
set
{
if ( value != null)
if( value.Length > 64)
throw new ArgumentOutOfRangeException("Invalid value for Email", value, value.ToString());
m_IsChanged |= (m_Email != value); m_Email = value;
}
}
/**//// <summary>
/// 对象的值是否被改变
/// </summary>
public bool IsChanged
{
get { return m_IsChanged; }
}
/**//// <summary>
/// 对象是否已经被删除
/// </summary>
public bool IsDeleted
{
get { return m_IsDeleted; }
}
#endregion
公有函数#region 公有函数
/**//// <summary>
/// 标记对象已删除
/// </summary>
public void MarkAsDeleted()
{
m_IsDeleted = true;
m_IsChanged = true;
}
#endregion
重写Equals和HashCode#region 重写Equals和HashCode
/**//// <summary>
/// 用唯一值实现Equals
/// </summary>
public override bool Equals( object obj )
{
if( this == obj ) return true;
if( ( obj == null ) || ( obj.GetType() != this.GetType() ) ) return false;
User castObj = (User)obj;
return ( castObj != null ) &&
( this.m_UserId == castObj.UserId );
}
/**//// <summary>
/// 用唯一值实现GetHashCode
/// </summary>
public override int GetHashCode()
{
int hash = 57;
hash = 27 * hash * m_UserId.GetHashCode();
return hash;
}
#endregion
}
}
<?
xml version="1.0" encoding="utf-8"
?>
<
hibernate-mapping
xmlns
="urn:nhibernate-mapping-2.0"
>
<
class
name
="MyNamePlace.User,MyAssembly"
table
="T_User"
>
<
id
name
="UserId"
column
="UserId"
type
="Int32"
unsaved-value
="0"
>
<
generator
class
="native"
/>
</
id
>
<
property
column
="UserName"
type
="String"
name
="UserName"
not-null
="true"
length
="64"
/>
<
property
column
="Password"
type
="String"
name
="Password"
not-null
="true"
length
="32"
/>
<
property
column
="Email"
type
="String"
name
="Email"
length
="64"
/>
</
class
>
</
hibernate-mapping
>
备注:
我的数据库表名以"T_"开头,生成类时我会用"_"后面的内容。例如:T_Parent对应的类是Parent。如果你的表名中没有"_"。将会取表名做类名。
如果你在设计数据表时把字段的描述加上,生成的代码文件的注释中将会有属性的描述。
注意:在把他们加入Visual Studio后别忘了设置为嵌入的资源。
生成关系
在Template Browser里面的NHibernate找到"DDL NHibernate Relation Mapping"。运行此模版
选择你需要的表,需要的关系。点OK。
我们以双向的one-to-many为例
你可以看到下面的生成代码。
//
Parent
<
bag name
=
"
Childs
"
cascade
=
"
all
"
lazy
=
"
true
"
inverse
=
"
true
"
>
<
key column
=
"
ParentId
"
></
key
>
<
one
-
to
-
many
class
=
"
MyNamePlace.Child,MyAssembly
"
></
one
-
to
-
many
>
</
bag
>
private
IList m_Child
=
new
ArrayList();
public
IList Childs
{
get{return m_Child;}
set{m_Child=value;}
}
//
Child
<
many
-
to
-
one name
=
"
Parent
"
column
=
"
ParentId
"
class
=
"
MyNamePlace.Parent,MyAssembly
"
/>
private
Parent m_Parent;
public
Parent Parent
{
get{return m_Parent;}
set{m_Parent=value;}
}
把他们拷贝到你生成的模版文件里面。“//Parent”后面的拷贝到Parent的映射类文件和.hbm.xml文件中。“//Child”后面的拷贝到Child的映射类文件和.hbm.xml文件中。
注意:需要把Child类和.hbm.xml里的ParentId去掉,不然会出现两个属性映射到一个字段的错误。
DDL NHibernate Relation Mapping模板使用注意:
保持主外键的名称一致,比如T_Parent中主键名为ParetId,T_Child中与其参照的外键名也为ParentId。
主表先选择,Parent-Child关系中先选择Parent,Person-Employee关系中先选择Person。
多对多关系才会用到中间表下拉框。
其他的关系生成操作方法类似,我不再复述。
如果你对关联不是很熟悉请参见NHibernate的关联映射(one-to-one,one-to-many,many-to-many)以及cascade分析。本模版生成的文件都使用NHibernate的关联映射(one-to-one,one-to-many,many-to-many)以及cascade分析一文的典型设置。可以满足绝大部分的情况。当然你也可以适当修改后使用。
模版更新:
增加了对Guid主键的支持,中文的注释,其他代码改善,部分代码提取到自定义的基类。
2006.8.24 修改部分bug
很多人反应模版使用问题,鉴于我这里没有.net1.0或者1.1的环境,所以把代码给出来,可以自己编译一个dll。
DDLNHibernateDotNetScriptTemplate
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using Dnp.Utils;
using MyMeta;
using Zeus;
using Zeus.DotNetScript;
using Zeus.UserInterface;
namespace DDLLY.MyGenerationTemplate
{
public abstract class DDLNHibernateDotNetScriptTemplate : _DotNetScriptTemplate
{
protected GuiController ui;
protected dbRoot MyMeta;
protected Utils DnpUtils;
public DDLNHibernateDotNetScriptTemplate(IZeusContext context)
: base(context)
{
ui = context.Objects["ui"] as GuiController;
MyMeta = context.Objects["MyMeta"] as dbRoot;
DnpUtils = context.Objects["DnpUtils"] as Utils;
}
/**//// <summary>
/// 前缀
/// </summary>
protected string _prefix;
/**//// <summary>
/// 创建XML
/// </summary>
protected bool _CreatingXML = false;
protected string _NullSufix;
protected 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 "string":
retVal = "String";
break;
}
return retVal;
}
//protected string ColumnToMemberVariable(IColumn Column)
//{
// return _prefix + UniqueColumn(Column).ToLower();
//}
//protected string ColumnToPropertyName(IColumn Column)
//{
// return ToPascalCase(UniqueColumn(Column));
//}
//protected string ColumnToArgumentName(IColumn Column)
//{
// return UniqueColumn(Column).ToLower();
//}
//protected string ColumnToNHibernateProperty(IColumn Column)
//{
// return _prefix + UniqueColumn(Column);
//}
// nhibernate doesn't have these, so use the existing types
protected string ColumnToNHibernateType(IColumn Column)
{
string retVal = Column.LanguageType;
switch (retVal)
{
case "sbyte":
retVal = "byte";
break;
case "uint":
retVal = "int";
break;
case "ulong":
retVal = "long";
break;
case "ushort":
retVal = "short";
break;
case "bool":
case "decimal":
case "float":
case "byte":
case "short":
case "int":
case "long":
if (!_CreatingXML)
{
if (Column.IsNullable)
{
retVal = retVal + _NullSufix;
}
}
break;
}
return retVal;
}
/**////// <summary>
///// 首字母大写
///// </summary>
///// <param name="name"></param>
///// <returns></returns>
//protected string ToLeadingCaps(string name)
//{
// char[] chars = name.ToLower().ToCharArray();
// chars[0] = Char.ToUpper(chars[0]);
// return new string(chars);
//}
/**//// <summary>
/// 首字母小写
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
private string ToLeadingLower(string name)
{
char[] chars = name.ToCharArray();
chars[0] = Char.ToLower(chars[0]);
return new string(chars);
}
/**//// <summary>
/// 私有成员名
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
protected string ToVariableName(string name)
{
return _prefix + name;
}
/**//// <summary>
/// 参数名
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
protected string ToArgumentName(string name)
{
return ToLeadingLower(name);
}
/**////// <summary>
///// 统计必需(不允许空)的的字段个数
///// </summary>
///// <param name="Columns"></param>
///// <returns></returns>
//protected int CountRequiredFields(IColumns Columns)
//{
// return Columns.Count - CountNullableFields(Columns);
//}
/**////// <summary>
///// 统计允许为空的字段个数
///// </summary>
///// <param name="Columns"></param>
///// <returns></returns>
//protected int CountNullableFields(IColumns Columns)
//{
// int i = 0;
// foreach (IColumn c in Columns)
// {
// if (c.IsNullable)
// {
// i++;
// }
// }
// return i;
//}
/**//// <summary>
/// 统计唯一字段的个数(非空且为主键)
/// </summary>
/// <param name="Columns"></param>
/// <returns></returns>
protected int CountUniqueFields(IColumns Columns)
{
int i = 0;
foreach (IColumn c in Columns)
{
if (!c.IsNullable && c.IsInPrimaryKey)
{
i++;
}
}
return i;
}
/**//// <summary>
/// 根据IColumn获得不同的Generator
/// </summary>
/// <param name="Column"></param>
/// <returns></returns>
protected string GetGeneratorString(IColumn Column)
{
if (Column.DataTypeName == "uniqueidentifier")
{
return "guid";
}
if(Column.IsAutoKey)
{
return "native";
}
else
{
return "assigned";
}
}
/**//// <summary>
/// 表名转换为类名
/// </summary>
/// <param name="tableName"></param>
/// <returns></returns>
protected string TableNameToClassName(string tableName)
{
int index = tableName.LastIndexOf("_");
return tableName.Substring(index + 1);
}
}
}
需要引用以下类库(都在MyGeneration的安装路径里):
Dnp.Utils.dll
DotNetScriptingEngine.dll
MyMeta.dll
PluginInterfaces.dll
Zeus.dll