2011-03-18 83 views
1

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

我碰到詹姆斯·科瓦奇博客文章Testing Immutable Entities with NHibernate

,他做了类似的事情时,他改变从一成不变到可变类,但我不能这个申请改变发电机类型。任何帮助,将不胜感激。

+0

可能的[NHibernate - 如何动态切换ID生成器?](http://stackoverflow.com/q/5089066/634872) – 2011-03-18 13:45:34

+0

嗨Florian,在你指的是,解决方案是切换到流利的NHibernate。如果无论如何,我想避免这种情况(必须重构所有映射) – zszep 2011-03-19 08:57:47

回答

7

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

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

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

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

这里是我用来创建SessionFacory的方法的修改版本。 (我把一个布尔值作为参数,在这里,但在我的代码使用枚举。)

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; 
} 

编辑:

如果你只是想在运行时修改的生成器类,你可以修改configuation构建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(禁用多到一):

要为许多到一个属性禁用映射一个非空属性,尝试以下操作:

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

+0

谢谢Florian,但这正是我想要避免的:必须为每个实体使用不同的hbm文件。你应该阅读詹姆斯科瓦茨的文章我链接在我的问题。1 hbm文件似乎可以做到这一点。他用这个不可改变的属性来做这件事。我只是无法弄清楚如何用发生器做到这一点。 Config类有很多属性,尽管我尝试过,但我无法弄清楚如何去做。 – zszep 2011-03-19 14:27:20

+0

@Željko对不起,我以为它只是一个或两个实体。我用另一种解决方案修改了我的答案 – 2011-03-19 20:02:09

+0

伟大的弗洛里安,这正是我正在寻找的。 – zszep 2011-03-20 07:19:22

相关问题