2013-08-23 23 views
6

Câu trả lời đầu tiên cho câu hỏi này: What to do when bit mask (flags) enum gets too large là chính xác những gì tôi đang cố gắng làm, chỉ tôi không biết làm thế nào để lưu trữ nó trong cơ sở dữ liệu bằng cách sử dụng LINQ to SQL và liên kết nó với người dùng mà không cần tạo 2 bảng cho mỗi nhóm điều/logic.Bitmask (cờ) enum vượt quá 64 với bitarray với nhóm logic được lưu trữ trong cơ sở dữ liệu

này được giải thích tốt nhất thông qua mã (đây là những LINQPad thân thiện mặc dù không đầy đủ):

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

mong muốn Kịch bản:

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

nỗ lực đang bổ sung:

WPF permission-based authorization using Enum Flag Bit

+0

Tôi không nghĩ rằng bạn sẽ cần hai bảng cho mỗi nhóm hợp lý. Nếu bạn sử dụng bitmasking cho enums của bạn và đã tạo/xóa/cập nhật trong một và thing1/thing2/thing3 trong một cái khác thì bạn chỉ có thể lặp qua enum và lưu trữ một hàng trong DB cho mỗi cặp logic cho người dùng, bạn cũng sẽ chỉ lưu trữ các cặp logic áp dụng cho người dùng, vì vậy, giống như bốn hàng tối đa. Một cột cho Tạo/Cập nhật/Xóa/Đọc (mỗi cột trong hàng của riêng chúng) và cột thứ hai là một bitmask của thing1/thing2/thing3. Tôi không nghĩ rằng bốn cột là quá nhiều thêm ... - Tôi có thể thiếu một cái gì đó mặc dù ... :) – Faraday

Trả lời

3

Không chắc bạn hoàn toàn hiểu cách cờ hoạt động. Lý do bạn sử dụng toán tử dịch chuyển trái là vì vậy enums của bạn sẽ là số mũ của giá trị sau.

Thuộc tính cờ là để cho .NET biết rằng giá trị của enum của bạn có thể là bội số.

Ví dụ nếu bạn mất ThingA và ThingB của bạn và thêm chúng (48)

Console.Write((Permissions)48));

Giá trị trả lại là cả hai ThingA và ThingB. Bạn chỉ có thể lưu nó dưới dạng một đơn ulong trong cơ sở dữ liệu, mã của bạn sẽ có thể tìm ra phần còn lại.

Các vấn đề liên quan