Enum with [Flags]
The most efficient way to support your scenario is to use an Enum
which has the FlagsAttribute
on it (this requires at least EntityFramework 5):
public class PermissionForm
{
public int Id {get; set;}
public string Name {get; set;}
public PermissionItem Permissions {get; set;}
}
[Flags]
public enum PermissionItem : short
{
EDIT = 1,
SHARE = 2,
ADMIN = 4 // note that each value must be a power of 2
}
Which doesn't need any particular mapping:
public PermissionForMap()
{
this.ToTable("PermissionForm").HasKey(p => p.Id);
this.Property(p => p.Name).HasColumnName("Name").HasMaxLength(30);
this.Property(p => p.Permissions).HasColumnName("Permissions"); // this is redundant, it's just to replicate your behavior
}
This way you may manage permissions using just the bitwise operators &
(AND
), |
(OR
), ^
(XOR
) and ~
(complement).
This will simplify your model and avoids the use of another table (which also requires joins inside your queries).
Example
Get all entities which have SHARE
permission:
var query = _dbContext.PermissionForms.Where(p => p.PermissionItem & PermissionItem.SHARE > 0);
If you use EntityFramework 6.1+ you may also use the built-in method HasFlag:
var query = _dbContext.PermissionForms.Where(p => p.PermissionItem.HasFlag(PermissionItem.SHARE));
Set multiple permission to an entity:
var permission = new PermissionForm
{
Name = "MyName",
Permissions = PermissionItem.EDIT | PermissionItem. SHARE // this has EDIT and also SHARE
};
Table mapping
If you really want to map your relationship to a table (which, in my opinion, is useless and inefficient for your scenario), you need to create a class, whici is supported by EntityFramework as an entity:
public class PermissionForm
{
public PermissionForm()
{
Permissions = new HashSet<PermissionEntity>();
}
public int Id {get; set;}
public string Name {get; set;}
public virtual ICollection<PermissionEntity> Permissions {get; set;}
}
public class PermissionEntity
{
public int PermissionFormId { get; set; }
public PermissionItem PermissionItem { get; set; }
public virtual PermissionForm PermissionForm { get; set; }
}
public enum PermissionItem : short
{
EDIT = 1,
SHARE = 2,
ADMIN = 3
}
And map it as any other navigation property for your model:
public class PermissionForMap : EntityTypeConfiguration<PermissionForm>
{
public PermissionForMap()
{
this.ToTable("PermissionForm").HasKey(p => p.Id);
this.Property(p => p.Name).HasColumnName("Name").HasMaxLength(30);
this.HasMany(p => p.Permissions)
.WithRequired(e => e.PermissionForm)
.HasForeignKey(e => e.PermissionFormId);
}
}
public class PermissionEntityMap : EntityTypeConfiguration<PermissionEntity>
{
public PermissionEntityMap()
{
ToTable("PermissionEntities")
.HasKey(e => new { e.PermissionFormId, e.PermissionItem }):
}
}