在NHibernate类映射中将id生成器动态更改为“已赋值”

时间:2011-03-18 13:14:41

标签: nhibernate

我正在基于NHibernate的winforms应用程序中进行一些批量插入。如果我可以在程序执行期间动态地将ID生成器类型从“guid.comb”更改为“已分配”,那将对我有很大帮助。

我遇到了James Kovacs的博客条目Testing Immutable Entities with NHibernate

当他将类从immutable更改为mutable时,他做了类似的事情,但我不能将其应用于更改生成器类型。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:7)

正如我在评论中链接到的问题的答案中所述,在创建SessionFactory之后,您无法更改它。因此,您唯一的选择是保持SessionFactory的第二个实例(最好也作为Singleton)。这不必与第一个同时创建。您可以在需要时创建它,但由于创建非常昂贵,建议创建一次并保留它。

但是,如果您真的只需要在应用程序运行时期间只发生一次或两次的批量插入,那么您也可以在操作后将其删除。

这就是理论,现在是实际的部分。简单的方法是获得Entity.hbm.xml文件的副本,您只需更改生成器属性即可。要创建SessionFactory,您需要提供一个参数(可能是一个枚举),以便您可以决定使用哪些.hbm.xml文件以及忽略哪些文件。

我建议命名默认的hbm文件Entity.Default.hbm.xml和修改后的一个Entity.Special.hbm.xml。所有其他的hbm文件都可以保留其名称。

这是我用来创建SessionFacory的方法的修改版本。 (我把bool作为参数放在这里,但在我的代码中我使用了枚举。)

private ISessionFactory BuildSessionFactory(bool useSpecialHbmFiles)
{
    Configuration config = new Configuration();

    config.SetProperty(NHibernate.Cfg.Environment.ConnectionProvider, "...");
    config.SetProperty(NHibernate.Cfg.Environment.Dialect, "...");
    config.SetProperty(NHibernate.Cfg.Environment.ConnectionDriver, "...");
    config.SetProperty(NHibernate.Cfg.Environment.ConnectionString, "...");
    config.SetProperty(NHibernate.Cfg.Environment.Isolation, "Serializable");
    config.SetProperty(NHibernate.Cfg.Environment.ProxyFactoryFactoryClass, "...");
    config.SetProperty(NHibernate.Cfg.Environment.ShowSql, "true");
    config.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, "none");

    // filter hbm Files

    // Set reference to entity assembly
    System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(MyEntity));

    // get Resource-files
    string[] resources = assembly.GetManifestResourceNames();

    // scan through all the hbm files and filter them according to the parameter
    foreach (string hbmFile in resources)
    {
        // This filtering here could probably be done simpler, but this is easy to understand
        bool addFile = false;
        // ignore any file that does not end with .hbm.xml
        if (hbmFile.EndsWith(".hbm.xml"))
        {
            if (hbmFile.ToLower().EndsWith(".default.hbm.xml"))
            {
                if (!useSpecialHbmFiles)
                {
                    // we want that file for this SessionFactory
                    addFile = true;
                }
            }
            else if (hbmFile.ToLower().EndsWith(".special.hbm.xml"))
            {
                if (useSpecialHbmFiles)
                {
                    // we want that file for this SessionFactory
                    addFile = true;
                }
            }
            else
            {
                // neither default nor special -> we want that file no matter what
                addFile = true;
            }
            if (addFile)
            {
                using (System.IO.StreamReader sr = new System.IO.StreamReader(assembly.GetManifestResourceStream(hbmFile)))
                {
                    string resourceContent = sr.ReadToEnd();
                    config.AddXmlString(resourceContent);
                }
            }
        }
    }

    // create Sessionfactory with the files we filtered
    ISessionFactory sessionFactory = config.BuildSessionFactory();
    return sessionFactory;
}

修改

如果您只想在运行时修改生成器类,可以在构建SessionFactory之前修改配置,如下所示:

// get the mapping's Key property
NHibernate.Mapping.SimpleValue keyValue = 
    config.GetClassMapping(typeof(MyEntity)).Key as NHibernate.Mapping.SimpleValue;
if (keyValue != null)
{
    // set GeneratorStrategy (the same string you would put in generator class="..." in the hbm file)
    keyValue.IdentifierGeneratorStrategy = "assigned";
}

现在,您可以将参数传递给CreateSessionFactory()方法并修改配置。您仍然需要第二个SessionFactory。您无法修改现有的。

编辑2(禁用多对一):

要在多对一属性的映射中禁用NOT-NULL属性,请尝试以下操作:

NHibernate.Mapping.PersistentClass mapping = config.GetClassMapping(typeof(MyEntity));

foreach (NHibernate.Mapping.Property prop in mapping.PropertyIterator)
{
    if (prop.Value is NHibernate.Mapping.ManyToOne)
    {
        prop.IsOptional = true;
    }
}

当然,这只有在DB中的外键列允许NULL值时才有效。