Динамически изменить генератор идентификаторов на «назначенный» в отображении класса NHibernate - PullRequest
1 голос
/ 18 марта 2011

Я делаю массовые вставки в приложение winforms, основанное на NHibernate.Мне было бы очень полезно, если бы я мог динамически изменить тип генератора идентификаторов с «guid.comb» на «назначенный» во время выполнения программы.

Я наткнулся на запись в блоге Джеймса Ковача Проверка неизменяемогоОбъекты с NHibernate

, где он делает аналогичную вещь, когда меняет класс с неизменяемого на изменяемый, но я просто не могу применить это для изменения типа генератора.Любая помощь будет оценена.

1 Ответ

7 голосов
/ 19 марта 2011

Как указано в ответе на вопрос, на который я ссылался в моем комментарии, вы не можете изменить его после создания SessionFactory.Поэтому единственный вариант, который у вас есть, - хранить второй экземпляр SessionFactory (предпочтительно также как Singleton).Это не должно быть создано одновременно с первым.Вы можете создать его, когда это необходимо, но так как создание довольно дорого, рекомендуется создать его один раз и сохранить.

Однако, если вам действительно нужно это только для массовой вставки, которая происходит только один или два раза во время выполнения приложения, то вы также можете избавиться от нее после операции.

Этобыла теория, теперь к практической части.Самый простой способ - получить копию файла Entity.hbm.xml, в котором вы просто измените атрибут генератора.Для создания SessionFactory вам необходимо предоставить параметр (возможно, Enum), чтобы вы могли решить, какие файлы .hbm.xml использовать, а какие игнорировать.

Я предлагаю назвать hbm-файл по умолчанию Entity.Default.hbm.xml и модифицированный Entity.Special.hbm.xml.Все остальные файлы hbm могут сохранять свои имена.

Вот модифицированная версия метода, который я использую для создания SessionFacory.(Я помещаю здесь bool в качестве параметра, но в своем коде я использую 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 следующим образом:

// 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 (отключение Many-To-One):

Чтобы отключить свойство NOT-NULL в отображении для many-toодин-один свойства, попробуйте следующее:

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

Конечно, это будет работать, только если столбец внешнего ключа в БД допускает значения NULL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...