1.原理
就是通过反射查找相应对象上的标签,然后动态生成与之前对应的hbm.xml流,然后加载至Configuration中。可见通过该种方式最重要的是相应的对象上加上正确并且需要的标签。这样就可以不再写或修改那烦人的xml文件。
2.准备工作
必须导入NHibernate.Mapping.Attributes命名空间,该命名空间属于NHibernate.Mapping.Attributes.dll文件中,该文件在NHibernateContrib-0.9.0.0中,可以到NHibernate网站下载。本文测试所采用的NHibernate和NHibernateContrib均是在0.9.0.0上测试通过。
3.如何加入标签
a.class上至少需加上[ClassAttribute(Table=Children)]
对应生成的xml片断如下
<class name="Models.Children, Models" table="Children">
b.Id上加上如下所示标签
[Id(0, Name="Id",TypeType=typeof (int),Column="Id",UnsavedValue="0")]
[Key(1)]
[Generator(2, class="native")]
public int Id
{
get { return _id; }
set { _id = value; }
}
其中0,1,2表示生成xml文件时属性的顺序,以上的标签最后生成可能是以下xml片断
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native" />
</id>
c.其他一般属性需加上如下标签
[PropertyAttribute(Column="PName",Length=50,TypeType=typeof(String))]
public string PName
{
get { return _pName; }
set { _pName = value; }
}
对应xml片断
<property name="PName" type="String" column="PName" length="50" />
d.对于一对多情况加上如下标签
[Bag(0,Table="Children", Lazy=true, Cascade=CascadeStyle.All)]
[Key(1, Column="ParentId")]
[OneToManyAttribute(2, ClassType=typeof(Children))]
public IList Children
{
get { return _children; }
set { _children = value; }
}
对应xml片断如下
<bag name="Children" table="Children" lazy="true" cascade="all">
<key column="ParentId" />
<one-to-many class="Models.Children, Models" />
</bag>
e.对于多对一的情况加上如下标签
[ManyToOne(0, ClassType=typeof (Parent),Column="ParentId",OuterJoin = OuterJoinStrategy.True)]
public Parent Parent
{
get { return _parent; }
set { _parent = value; }
}
对应的xml片断
<many-to-one name="Parent" class="Models.Parent, Models" column="ParentId" outer-join="true" />
4.类写好了,标签也加上了,可以采用如下方式加入到Configuration
Configuration cfg = new Configuration();
using(MemoryStream stream = new MemoryStream())
{
for(int i=0;i<config.Count;i++)
{
HbmSerializer.Serialize(stream, System.Reflection.Assembly.Load("models"));
stream.Position = 0;
cfg.AddInputStream(stream);
}
}
4.容易出现的问题
漏掉标签,如:在Id上漏掉Name导致Search出来的对象Id都是0,漏掉级联或是其他
5.解决方法
a.可以将其动态产生的xml文件流输出到一个xml文件中,然后将输出的xml文件和之前的xml文件比对容易发现问题
输出到xml文件的代码如下:
FileStream fs = new FileStream(@"d:\DynamicHibernateMapping.xml",FileMode.Create);
fs.Write(stream.ToArray(),0,(Int32)stream.Length);
fs.Close();
b.列出一个属性标签清单,进行对比也可以
6.其他问题
欢迎私下交流,MSN:eJimGao@msn.com
7.Table DDL
CREATE TABLE [dbo].[Children] (
[Id] [int] IDENTITY (1, 1) NOT NULL ,
[CName] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[ParentId] [int] NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Parent] (
[Id] [int] IDENTITY (1, 1) NOT NULL ,
[PName] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL
) ON [PRIMARY]
1. 配置log4net.
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="rollingFile" type="log4net.Appender.RollingFileAppender,log4net" >
<param name="File" value="D:\log.txt" />
<param name="AppendToFile" value="false" />
<param name="RollingStyle" value="Date" />
<param name="DatePattern" value="yyyy.MM.dd" />
<param name="StaticLogFileName" value="true" />
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] <%X{auth}> - %m%n" />
</layout>
</appender>
<root>
<!--如果只需要看看Sql设置INFO就够了,如果你要调试可以设置为DEBUG或ALL-->
<priority value="INFO" />
<appender-ref ref="rollingFile" />
</root>
</log4net>
a). 将上面的xml保存为log4net.cfg.xml文件,放在工程根目录下并在该文件的属性窗口中选择”始终复制“,这样在每次编译时,此文件都将被复制到工程输出目录中,该输出目录是VS搜索路径的一部分,在代码中可以访问。
b). 在程序初始化的地方使用下面一条语句,用来加载log4net.cfg.xml配置文件。
XmlConfigurator.Configure(new FileInfo("log4net.cfg.xml")); //初始化log4net
c). 在类中创建一个ILog
private static readonly ILog log = LogManager.GetLogger(typeof(类名));
d). 使用log
log.Info("MyTestInitialize");
log.Debug("MyTestInitialize");
log.Warn("MyTestInitialize");
log.Error("MyTestInitialize");
最终,如果一切顺利的话,NHiberante和自己的日志都将被输出到D:\log.txt中。