2011-03-18 41 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