Как сопоставить перечисление как значение int с помощью свободного NHibernate?

88

Вопрос говорит об этом на самом деле, по умолчанию он отображается как файл, stringно мне нужно, чтобы он отображался как int.

В настоящее время я использую PersistenceModelдля установки своих соглашений, если это имеет значение. Заранее спасибо.

Обновление. Обнаружил, что установка последней версии кода из магистрали решила мои проблемы.

Гарри Шатлер
источник
5
если вы решили проблему самостоятельно, вы должны ответить на него, а затем отметить его как правильный ответ, чтобы будущие поисковики нашли его.
Джефф Мартин,
Не могли бы вы опубликовать ответ?
mxmissile
Готово, ребята. Извините за задержку. Я не совсем понимал, что мне делать с вопросом, который больше не был вопросом, поскольку мне просто нужна была последняя версия библиотек.
Гарри Шатлер,
2
Пища для роботов Google: я получал «незаконный доступ к загрузке коллекции», прежде чем реализовать это для моего сопоставления перечисления.
4imble

Ответы:

84

Способ определения этого соглашения иногда менялся назад, теперь он:

public class EnumConvention : IUserTypeConvention
{
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Property.PropertyType.IsEnum);
    }

    public void Apply(IPropertyInstance target)
    {
        target.CustomType(target.Property.PropertyType);
    }
}
Жюльен
источник
4
Это правильный ответ для самой последней версии fluent nhibernate
Шон Чемберс,
Удар. ^^ Что сказал Шон.
Мартин Сучанек
1
Похоже, он отлично работает для всех типов перечислений, но что, если вы хотите, чтобы некоторые из них были строками, а некоторые - целыми числами? Я думаю, это должно быть настроено на уровне сопоставления свойств.
UpTheCreek
4
См. Ответ @SztupY ниже, который расширяет это, чтобы разрешить перечисления, допускающие значение NULL. stackoverflow.com/questions/439003/…
Джон Адамс
45

Итак, как уже упоминалось, получение последней версии Fluent NHibernate из магистрали привело меня туда, где я должен был быть. Пример сопоставления перечисления с последним кодом:

Map(quote => quote.Status).CustomTypeIs(typeof(QuoteStatus));

Пользовательский тип заставляет его обрабатывать как экземпляр перечисления, а не использовать GenericEnumMapper<TEnum>.

На самом деле я рассматриваю возможность отправки патча, чтобы иметь возможность переключаться между сопоставителем перечислений, который сохраняет строку, и тем, который сохраняет int, поскольку это похоже на то, что вы должны иметь возможность установить в качестве соглашения.


Это всплыло во время моей недавней деятельности, и в новых версиях Fluent NHibernate все изменилось, чтобы упростить задачу.

Чтобы все перечисления отображались как целые числа, вы можете создать такое соглашение:

public class EnumConvention : IUserTypeConvention
{
    public bool Accept(IProperty target)
    {
        return target.PropertyType.IsEnum;
    }

    public void Apply(IProperty target)
    {
        target.CustomTypeIs(target.PropertyType);
    }

    public bool Accept(Type type)
    {
        return type.IsEnum;
    }
}

Тогда ваше отображение должно быть:

Map(quote => quote.Status);

Вы добавляете соглашение к отображению Fluent NHibernate следующим образом:

Fluently.Configure(nHibConfig)
    .Mappings(mappingConfiguration =>
    {
        mappingConfiguration.FluentMappings
            .ConventionDiscovery.AddFromAssemblyOf<EnumConvention>();
    })
    ./* other configuration */
Гарри Шатлер
источник
3
с "режимом int" по умолчанию. Кто сохраняет перечисления как строки ?!
Эндрю Баллок
4
Может быть устаревшая база данных с уже существующими строковыми значениями
Крис Хейнс,
4
+1 хайнес. @ Эндрю Баллок: ответьте на ваш вопрос: любой, кто имеет дело с базами данных реального мира.
Скай Сандерс,
Есть ли в FN интерфейс IProperty?
Tien Do
40

Не забывайте о перечислениях, допускающих значение NULL (например ExampleEnum? ExampleProperty)! Их нужно проверять отдельно. Вот как это делается с новой конфигурацией стиля FNH:

public class EnumConvention : IUserTypeConvention
{
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Property.PropertyType.IsEnum ||
            (x.Property.PropertyType.IsGenericType && 
             x.Property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) &&
             x.Property.PropertyType.GetGenericArguments()[0].IsEnum)
            );
    }

    public void Apply(IPropertyInstance target)
    {
        target.CustomType(target.Property.PropertyType);
    }
}
SztupY
источник
4
+1 За это дополнение! Первая версия не работает для перечислений, допускающих значение NULL (они остаются в виде строк).
longda
@SztupY Тип столбца в базе данных int? А когда типа accept Flags? Нравится:MyEnum.Active | MyEnum.Paused
ridermansb
@RidermandeSousaBarbosa: проверьте флаги здесь: stackoverflow.com/questions/2805661/…
SztupY
25

вот как я сопоставил свойство enum со значением int:

Map(x => x.Status).CustomType(typeof(Int32));

работает для меня!

Фелипе
источник
2
Спасибо за самый простой ответ
Майк
Единственное, что меня беспокоит, это то, что вы должны не забывать применять его к каждому перечислению. Вот для чего были созданы конвенции.
Гарри Шатлер,
Это работает для чтения, но не удалось, когда я попробовал запросить критерии. Однако установка соглашения (см. Ответ на этот вопрос) работала во всех случаях, которые я пробовал.
Thomas Bratt
Что ж, я думал, что это здорово, но это вызовет проблемы: см. Этот пост. nhforge.org/blogs/nhibernate/archive/2008/10/20/…
UpTheCreek
@UpTheCreek Кажется, что это было исправлено и теперь рекомендовано Джеймсом Грегори из команды NH: mail-archive.com/fluent-nhibernate@googlegroups.com/…
Илья Коган
1

Для тех, кто использует Fluent NHibernate с Automapping (и, возможно, контейнер IoC):

Это IUserTypeConventionкак ответ @ Julien выше: https://stackoverflow.com/a/1706462/878612

public class EnumConvention : IUserTypeConvention
{
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Property.PropertyType.IsEnum);
    }

    public void Apply(IPropertyInstance target)
    {
        target.CustomType(target.Property.PropertyType);
    }
}

Конфигурацию Fluent NHibernate Automapping можно настроить следующим образом:

    protected virtual ISessionFactory CreateSessionFactory()
    {
        return Fluently.Configure()
            .Database(SetupDatabase)
            .Mappings(mappingConfiguration =>
                {
                    mappingConfiguration.AutoMappings
                        .Add(CreateAutomappings);
                }
            ).BuildSessionFactory();
    }

    protected virtual IPersistenceConfigurer SetupDatabase()
    {
        return MsSqlConfiguration.MsSql2008.UseOuterJoin()
        .ConnectionString(x => 
             x.FromConnectionStringWithKey("AppDatabase")) // In Web.config
        .ShowSql();
    }

    protected static AutoPersistenceModel CreateAutomappings()
    {
        return AutoMap.AssemblyOf<ClassInAnAssemblyToBeMapped>(
            new EntityAutomapConfiguration())
            .Conventions.Setup(c =>
                {
                    // Other IUserTypeConvention classes here
                    c.Add<EnumConvention>();
                });
    }

* Затем его CreateSessionFactoryможно легко использовать в IoC, таком как Castle Windsor (с использованием PersistenceFacility и установщика). *

    Kernel.Register(
        Component.For<ISessionFactory>()
            .UsingFactoryMethod(() => CreateSessionFactory()),
            Component.For<ISession>()
            .UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession())
            .LifestylePerWebRequest() 
    );
lko
источник
0

Вы можете создать NHibernate IUserTypeи указать его CustomTypeIs<T>()на карте свойств.

Джеймс Грегори
источник
0

Вы должны сохранить значения как int / tinyint в своей таблице БД. Для сопоставления вашего перечисления вам необходимо правильно указать сопоставление. См. Ниже образец сопоставления и перечисления,

Класс отображения

открытый класс TransactionMap: ClassMap Transaction
{
    public TransactionMap ()
    {
        // Другие сопоставления
        .....
        // Отображение для enum
        Карта (x => x.Status, «Статус»). CustomType ();

        Таблица («Сделка»);
    }
}

Enum

публичное перечисление TransactionStatus
{
   Ожидание = 1,
   Обработано = 2,
   RolledBack = 3,
   Заблокировано = 4,
   Возвращено = 5,
   AlreadyProcessed = 6,
}
Аркадас Килич
источник