使用 EntityTypeConfiguration 映射 short[]

Mapping short[] with EntityTpeConfiguration

有人可以解释我应该如何使用 EntityTypeConfiguration 将实体映射到数组或原始值列表。我有以下实体和枚举:

public class PermissionForm
{
   public int Id {get; set;}

   public string Name {get; set;}

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

public enum PermissionItem : short
{
   EDIT = 1,
   SHARE = 2,
   ADMIN = 3
}

我一直在寻找与我试图了解它是如何工作的东西类似的东西,但没有成功。

我希望数据库中的表类似于:

| PermissionForm |
| -------------- |
| Id             |
| Name           |

|  PermissionForm_PermissionItems |
| ------------------------------- |
| PermissionFormId                |
| PermissionItem_Value            |

到现在我得到了下面的代码,但我觉得不是很接近正确:

public PermissionForMap()
{
    this.ToTable("PermissionForm").HasKey(p => p.Id);

    this.Property(p => p.Name).HasColumnName("Name").HasMaxLength(30);
    this.Map(map =>
    {
       map.ToTable("PermissionsFormPermissionItem");
       map.Requires(p => p.Id);
       map.Properties(p => p.PermissionItems);
    });
}

枚举 [Flags]

支持您的方案的最有效方法是使用上面有 FlagsAttributeEnum(这至少需要 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
}

不需要任何特定映射:

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
}

通过这种方式,您可以仅使用按位运算符来管理权限 & (AND), | (OR), ^ (XOR) and ~ (complement)

这将简化您的模型并避免使用另一个 table(这也需要在您的查询中加入)。

例子

获取所有拥有SHARE权限的实体:

var query = _dbContext.PermissionForms.Where(p => p.PermissionItem & PermissionItem.SHARE > 0);

如果您使用 EntityFramework 6.1+,您也可以使用内置方法 HasFlag:

var query = _dbContext.PermissionForms.Where(p => p.PermissionItem.HasFlag(PermissionItem.SHARE));

为一个实体设置多重权限:

var permission = new PermissionForm
{
    Name = "MyName",
    Permissions = PermissionItem.EDIT | PermissionItem. SHARE // this has EDIT and also SHARE
};

Table映射

如果你真的想将你的关系映射到一个table(在我看来,这对你的场景来说是无用且低效的),你需要创建一个class,这是支持的由 EntityFramework 作为一个实体:

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
}

并将其映射为您模型的任何其他导航属性:

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 }):
    }
}