将 id 生成器动态更改为“已分配"在 NHibernate 类映射中 [英] Dynamically change the id generator to "assigned" in NHibernate class mapping

查看:47
本文介绍了将 id 生成器动态更改为“已分配"在 NHibernate 类映射中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am doing some bulk inserts in a winforms application based on NHibernate. It would be of great help to me If I could dynamically change the ID generator type from "guid.comb" to "assigned" during program execution.

我看到了 James Kovacs 的博客条目 Testing Immutable Entities与 NHibernate

I came across James Kovacs' Weblog entry Testing Immutable Entities with NHibernate

当他将类从不可变更改为可变时,他做了类似的事情,但我无法将其应用于更改生成器类型.任何帮助将不胜感激.

where he does a similar thing when he changes the class from immutable to mutable, but I just can't apply this to changing the generator type. Any help would be appreciated.

推荐答案

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

As stated in the answer to the question I linked to in my comment, you cannot change it after the SessionFactory has been created. Therefore, the only option you have is keeping a second instance of the SessionFactory (preferably also as a Singleton) around. That doesn't have to be created at the same time as the first. You can create it when needed, but since the creation is quite expensive, the recommendation is to create it once and keep it.

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

However, if you really only need it for a bulk insert that occurs only once or twice during the runtime of the application, then you could also get rid of it after the operation.

这就是理论,现在是实践部分.简单的方法是拥有一份 Entity.hbm.xml 文件的副本,您只需在其中更改生成器属性.为了创建 SessionFactory,您需要提供一个参数(可能是一个 Enum),以便您可以决定使用哪些 .hbm.xml 文件以及忽略哪些文件.

That was the theory, now to the practical part. The easy way would be having a copy of the Entity.hbm.xml file where you just change the generator attribute. For the creation of the SessionFactory you need to provide a parameter (maybe an Enum) so that you can decide which .hbm.xml files to use and which ones to ignore.

我建议将默认的 hbm 文件命名为 Entity.Default.hbm.xml,并将修改后的一个命名为 Entity.Special.hbm.xml.所有其他 hbm 文件都可以保留它们的名称.

I suggest naming the default hbm file Entity.Default.hbm.xml and the modified one Entity.Special.hbm.xml. All the other hbm files can keep their names.

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

Here is a modifed version of the method I use to create the SessionFacory. (I put a bool as parameter here but in my code I use an Enum.)

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 之前像这样修改配置:

If you only want to modify the generator class at runtime, you can modify the configuation before building the SessionFactory like this:

// 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.您不能修改现有的.

Now you can pass a parameter to your CreateSessionFactory() method and modify the configuration. You will still need a second SessionFactory. You cannot modify an existing one.

编辑 2(禁用多对一):

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

To disable a NOT-NULL property in the mapping for many-to-one properties, try the following:

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 值时才有效.

Of course, this will only work if the foreign-key column in the DB allows NULL values.

这篇关于将 id 生成器动态更改为“已分配"在 NHibernate 类映射中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆