FluentNHibernate и Enums - PullRequest
       19

FluentNHibernate и Enums

3 голосов
/ 11 июня 2009

У меня есть enum, называемый Permissions. Пользователю могут быть назначены разрешения, или разрешения могут быть назначены роли, и пользователю может быть назначена роль.

Пользователь и роль оба имеют свойство, подобное этому:

public virtual IList<Permission> Permissions { get; set; }

Я хочу использовать enum для Permissions, поэтому в моем коде я могу делать что-то вроде

public static bool UserHasPermission(Permission.DeleteUser)

Прямо сейчас у меня есть около 50 различных разрешений в моем перечислении. Было бы хорошо, если бы мне не пришлось заполнять зеркальный набор данных в базе данных. Мое перечисление выглядит так:

public enum Permission
    {
        //site permissions 1-99
        [StringValue("View Users")]
        ViewUser = 1,

        [StringValue("Add User")]
        AddUser = 2,

        [StringValue("Edit User")]
        EditUser = 3,

        [StringValue("Delete User")]
        DeleteUser = 4

        ...

}

В настоящее время у меня есть таблица для PermissionsId (int) и PermissionName (varchar (50)).

Вот мои таблицы с ролями. Пользовательская часть точно такая же, как и разрешения:

CREATE TABLE dbo.Roles
(
    RoleId                      int                 IDENTITY(2,1) NOT NULL,
    RoleName                    varchar (50)        NOT NULL,

    CONSTRAINT PK_Roles PRIMARY KEY CLUSTERED (RoleId)
)

CREATE TABLE dbo.RolePermissions
(
    RolePermissionId            int                 IDENTITY(1,1) NOT NULL,
    RoleId                      int                 NOT NULL,
    PermissionId                int                 NOT NULL,

    CONSTRAINT PK_RolePermissions PRIMARY KEY CLUSTERED (RolePermissionId),
    CONSTRAINT FK_RolePermissions_Roles FOREIGN KEY (RoleId) REFERENCES Roles(RoleId),
    CONSTRAINT U_RolePermissions UNIQUE(RoleId, PermissionId)
)

Тогда у меня есть таблица разрешений на случай, если она мне понадобится, но я просто не понимаю, как сопоставить поле id в RolePermissions или таблицу Permissions обратно с перечислением.

CREATE TABLE dbo.Permissions
(
    PermissionId                    int                 NOT NULL,
    PermissionName                  varchar (50)        NOT NULL,

    CONSTRAINT PK_Permissions PRIMARY KEY CLUSTERED (PermissionId)
)
  1. Можно ли сопоставить перечисление с таблицей?
  2. Должен ли я даже сопоставить это или я просто должен взять таблицу Permissions и в UserPermissions и RolePermissions оставить PermissionId только int и отобразить в перечисление?
  3. Если я сохраню таблицу разрешений, есть ли способ для nhibernate автоматически заполнить данные в таблице разрешений данными из перечисления?

Прямо сейчас у меня нет сопоставления с перечислением полномочий, кроме как что-то вроде этого:

HasManyToMany(x => x.Permissions)
                 .WithParentKeyColumn("RoleId")
                 .WithChildKeyColumn("PermissionId")
                 .WithTableName("RolePermissions")
                 .LazyLoad()
                 .Cascade.All();

К сожалению, это вызывает ошибку:

Ассоциация из таблицы RolePermissions относится к не нанесенному на карту учебный класс: GotRoleplay.Core.Domain.Model.Permission

Что я делаю не так с перечислениями? Существует ли стандартный способ или наилучшая практика для их использования с fluentnhibernate, когда перечисление представляет собой список значений объекта, а не только одно значение?

Ответы [ 2 ]

0 голосов
/ 16 июня 2009

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

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

Сначала я переименовал мое перечисление.

public enum PermissionCode
    {
        //site permissions 1-99
        [StringValue("View Users")]
        ViewUser = 1,

        [StringValue("Add User")]
        AddUser = 2,

        [StringValue("Edit User")]
        EditUser = 3,

        [StringValue("Delete User")]
        DeleteUser = 4,
    }

Затем я создал новый класс разрешений. Этот класс отражает базу данных и представляет собой просто int Id и строковое имя. Однако я добавил одно свойство для преобразования этого идентификатора в мое перечисление PermissionCode.

public class Permission
    {
        public virtual int PermissionId { get; set; }
        public virtual string PermissionName { get; set; }

        public virtual PermissionCode PermissionCode 
        {
            get
            {
                return (PermissionCode)PermissionId;
            }
        }
    }

Затем в моих объектах User и Role я ссылаюсь на Permission, и я все еще могу выполнять сопоставления, такие как bool UserHasPermission (PermissionCode.DeleteUser);

Затем в global.asax в Application_Start я проверю webconfig на наличие флага, который укажет, нужно ли перестраивать разрешения. Таким образом, я могу разрешить перестроение только тогда, когда мне нужно, без разрешения на вход и, возможно, для устранения ошибки. Это означает, что я поддерживаю только один список разрешений в моем перечислении, что идеально.

Конечно, общий подход не так удобен, как я хотел, но он работает. У кого-нибудь есть другие предложения?

0 голосов
/ 12 июня 2009

Просто чтобы убедиться, что я понимаю, вы пытаетесь просто сопоставить свойство enum в вашем классе с полем в базе данных? Если это так, то вот пример того, как это сделать:

public class Toy {
    public virtual int Id { get; private set; }
    public virtual string Name { get; set; }
    public virtual ToyCondition Condition { get; set; }
}

public enum ToyCondition {
    New,
    Used
}

public class ToyMap : ClassMap<Toy> {
    public ToyMap() {
        Id(x => x.Id);
        Map(x => x.Name);
        Map(x => x.Condition).CustomTypeIs(typeof(ToyCondition));
    }
}

После этого вы можете получить, установить и выполнить логику со свойством Condition, как обычно, используя перечисление ToyCondition.

Toy newToy = new Toy();
newToy.Condition = ToyCondition.New;
toyRepository.Save(newToy);

В базе данных для поля Condition это должно быть int. Я надеюсь, что это имело смысл и отвечает на ваш вопрос. Извините, если это не так, и я далеко.

Edit: Извините, я только что заметил, что вы задали этот вопрос, и кто-то дал вам тот же ответ, что и я. Я не думаю, что смогу тебе в этом помочь. (

...