书接上回,解决目前最后一个问题:根据模版mapping自动生成各个可能的XXX专用mapping。
上回简单的谈了一下思路
但是,在什么时机呢,由谁来做呢?可以有很多的选择。比如说可以在编译之前手动执行一个tool做这件事,然后把新得到的那些mapping都编译进去。但是这意味着每次客户追加一个XXX的可能取值,我们都需要重新编译我们的dll。这无疑是很麻烦的。
鉴于目前还不会实现完全动态的加载新的mapping,我给自己设定的目标是:手动改一处配置,然后重启一下进程。另外,为了获得更好的性能,希望已经创建好的mapping在下一次不需要重新copy-replace。
于是思路变成在BuildSessionFactory之前,读配置文件中的一个list(包含XXX的可能取值),看对应的assembly是否已经存在。若不存在emit一个出来并存在硬盘上,使下一次不用再次创建。
代码示例如下
private readonly XmlSerializer m_serializer = new XmlSerializer(typeof(HbmMapping));
private void EmbeddedHbmIntoMoudle(ModuleBuilder modBuilder, string replaceFrom, string replaceTo)
{
var templateAsm = Assembly.Load(TemplateAssemblyName);
foreach (var resourceName in templateAsm.GetManifestResourceNames())
{
if (resourceName.StartsWith(ReplacableResourceNamePrefix))
{
var mapping = m_serializer.Deserialize(templateAsm.GetManifestResourceStream(resourceName)) as HbmMapping;
foreach (var item in mapping.Items)
{
if (item is HbmClass)
{
ReplaceClassEntityName(item as HbmClass, replaceFrom, replaceTo);
}
else if (item is HbmJoinedSubclass)
{
ReplaceJoinSubClassEntityName(item as HbmJoinedSubclass, replaceFrom, replaceTo);
}
else
{
//ignore
}
}
var stream = new MemoryStream();
m_serializer.Serialize(stream, mapping);
modBuilder.DefineManifestResource(resourceName, stream, ResourceAttributes.Public);
}
else
{
//ignore
}
}
}