2013-08-23 5 views
6

La prima risposta a questa domanda: What to do when bit mask (flags) enum gets too large è esattamente ciò che sto cercando di fare, solo che non so come memorizzarlo nel database usando LINQ to SQL e legalo agli utenti senza creare 2 tabelle per ogni cosa/gruppo logico.Bitmask (flag) enumerazione oltre 64 con bitarray con raggruppamento logico memorizzato nel database

Questo si spiega meglio tramite codice (questi sono LINQPad cordiale anche se incompleto):

// Requirements: 
// 1) Using LINQ to SQL 
// 2) Track User's CRUD rights in different parts of an application (parts referred to below as 'Things') 
// For example: ThingA.Create, ThingB.Read, ThingB.Update, ThingC.Delete 
// Desired usage: if (User.IsAllowed(ThingA.Create)) { // allowed } else { // not allowed } 
// 3) Allow for more than 64 'Things' 
// 4) Do not want to refer to permissions using strings like User.IsAllowed("Create ThingA"); 

// 
// Scenario A: This works, but you would be limited to adding only 60 'Things' 
// Example usage: 
// User Bob = new User(); 
// var desiredPermissions = Permissions.Create | Permissions.ThingA; // Permission = Unique binary value combination of flags 
// if ((Bob.Permissions & desiredPermissions) == desiredPermissions) { // Bob has permission to Create ThingA 
[Flags] 
public enum Permissions : ulong 
{ 
    Create = 1 << 0, 
    Read = 1 << 1, 
    Update = 1 << 2, 
    Delete = 1 << 3, 

    // Limited to 60 'Things' 
    ThingA = 1 << 4, 
    ThingB = 1 << 5 
} 

// User Model 
[Table(Name="Users")] 
public class User 
{ 
    [Column(IsPrimaryKey = true)] 
    public string FName { get; set; } 

    [Column] 
    public Permissions Permissions { get; set; } 

    public User() 
    { 
    } 
} 

ScenarioB:

// 
// Scenario B: This would work too, but each new 'Thing' would need its own flag enum list stored in its own table (ThingXPermissions), 
// with another table linking ThingXPermissions.X to Users.ID (UserThingXPermissions) (yuck!) 
// Would like to avoid having to change database structure when adding more 'Things' in future. 

// User Model 
[Table(Name="Users")] 
public class User 
{ 
    [Column(IsPrimaryKey = true, IsDbGenerated = true)] 
    public int ID { get; set; } 

    private EntitySet<ThingAPermissions> userThingAPermissions = new EntitySet<ThingAPermissions>(); 
    [Association(Name = "FK_User_UserThingAPermissions", Storage = "userThingAPermissions", OtherKey = "FK_User_Id", ThisKey = "ID")] 
    public IEnumerable<ThingAPermissions> UserThingAPermissions 
    { get { return userThingAPermissions; } } 

    public IEnumerable<ThingAPermissions> ThingAPermissions 
    { get { return (from up in UserThingAPermissions select up.UserThingAPermissions).AsEnumerable(); } } 

    public User() 
    { 
    } 
} 

[Table(Name="UserThingAPermissions")] 
public class UserThingAPermissions 
{ 
    [Column(IsPrimaryKey = true)] 
    public int FK_User_Id; 

    private EntityRef<User> user; 
    [Association(IsForeignKey = true, ThisKey = "FK_User_Id")] 
    public User User 
    { 
     get { return user.Entity; } 
     set { user.Entity = value; } 
    } 

    [Column] 
    public ThingAPermissions ThingAPermissions { get; set; } 
} 

// ThingAPermissions 
[Flags] 
public enum ThingAPermissions : ulong 
{ 
    Create = 1 << 0, 
    Read = 1 << 1, 
    Update = 1 << 2, 
    Delete = 1 << 3 
} 

scenario desiderato:

// 
// Desired Scenario: Psuedo code of what I'd like to be able to do: 
// Single Permissions (CRUD) list 
// Single||simple Things list 
// Single||simple table associating UserX, ThingX, PermissionX 
// Example usage: 
// User Bob = new User(); 
// var desiredPermissions = Permissions.Create | Things.ThingZ; // Permission = Unique binary value combination of flags 
// if ((Bob.Permissions & desiredPermissions) == desiredPermissions) { // Bob has permission to Create ThingZ 
// Missing link: Combining enums and storing into database linked to user 
// e.g. 
// [Table = "UserPermissions"] 
// (User, Thing, Permission) 
// 1, ThingZ, Create 
// 1, ThingZ, Delete 
// 1, ThingX, Read 
// 2, ThingZ, Read 
// 2, ThingX, Delete 
[Flags] 
public enum Permissions : ulong 
{ 
    Create = 1 << 0, 
    Read = 1 << 1, 
    Update = 1 << 2, 
    Delete = 1 << 3 
} 

[Flags] 
public enum Things : ulong 
{ 
    ThingZ = 1 << 0, 
    ThingY = 1 << 1, 
    ThingX = 1 << 2, 
    ThingW = 1 << 3 
} 

[Table(Name="UserPermissions")] 
public class UserPermission 
{ 
    [Column(IsPrimaryKey = true)] 
    public int FK_User_Id; 

    private EntityRef<User> user; 
    [Association(IsForeignKey = true, ThisKey = "FK_User_Id")] 
    public User User 
    { 
     get { return user.Entity; } 
     set { user.Entity = value; } 
    } 

    [Column] 
    public int FK_Thing_Thing { get; set; } 

    private EntityRef<Things> thing; 
    [Association(IsForeignKey = true, ThisKey = "FK_User_Id")] 
    public User User 
    { 
     get { return user.Entity; } 
     set { user.Entity = value; } 
    } 

    [Column] 
    public Permissions Permission { get; set; } 
} 

Ulteriori tentativi di codice:

WPF permission-based authorization using Enum Flag Bit

+0

Non penso che avresti bisogno di due tabelle per ogni gruppo logico. Se hai usato la maschera dei bit per l'enumerazione e hai creato/elimina/aggiorna in uno e cosa1/cosa2/cosa3 in un altro, puoi semplicemente ripetere l'enumerazione e memorizzare una riga nel DB per ciascuna coppia logica per l'utente, inoltre memorizza solo le coppie logiche che si applicano all'utente, quindi come quattro righe max. Una colonna per Crea/Aggiorna/Elimina/Leggi (ciascuna nella propria riga) e una seconda colonna che era una maschera di bit di thing1/thing2/thing3. Non credo che quattro colonne siano troppo extra ... - Potrei mancare qualcosa però ... :) – Faraday

risposta

3

Non sei sicuro di aver capito come funzionano le bandiere. Il motivo per cui stai utilizzando l'operatore di spostamento a sinistra è che le tue enumerazioni saranno esponenti del seguente valore.

L'attributo flag consente a .NET di sapere che il valore dell'enumerazione potrebbe essere multiplo.

Per esempio se si prende il ThingA e ThingB e li (48)

Console.Write((Permissions)48));

Il valore restituito è SIA ThingA e ThingB aggiungere. Sarai in grado di salvarlo come singolo ulong nel database, il tuo codice sarà in grado di capire il resto.