繁体   English   中英

如何使用 EF 5 存储枚举列表

[英]How to store a List of enum using EF 5

我目前正在做一个代码优先的小项目:我必须创建一个电影数据库,并且像往常一样,每部电影可以有多个类型 (m:n)。 由于流派是不变的,我决定创建一个包含所有流派的枚举类型。

Movie表中,我有一个流派列表(枚举)。 显然这是错误的,因为您不能在数据库中存储枚举列表。

于是我开始寻找答案。 我遇到了很多解决方案,不幸的是它们都没有真正帮助我。 所以我决定问这个问题。 我知道这可能是重复的,但其他解决方案并没有真正的帮助。

我发现的一些解决方案是FlagsSmartEnum

我都试过了,但它并没有真正起作用。 您能否看看我的代码并告诉我我做错了什么,或者是否有另一种方法来转换枚举列表。

电影:

class Serie
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    [MaxLength(255)]
    public string Titel { get; set; } = "";

    public virtual List<Genres> Genres { get; } = new();
}

流派:

public sealed class Genres : SmartEnum<Genres>
{
    public static readonly Genres Drama = new(name: "Drama", value: 1);
    public static readonly Genres Crime = new(name: "Crime", value: 2);
    ...

    private Genres(string name, int value) : base(name, value)
    { }
}

PS:我知道我可以用额外的 class 来做到这一点,但我想用枚举来做到这一点。

这并不是真正的enum问题,而是您想要 model 多对多关系的事实。 如果您需要存储intstring的列表,那将是相同的。

要么你打破良好的做法,并在你的电影表中存储同一部电影的几行(电影的每种类型都有一行)。 在这种情况下,您将直接在数据库中存储一个enum 那真的很难看。

或者你的 model 是正确的,这意味着你需要一个存储你的流派的表。 该表可以以经典方式构建,具有主键 (Id) 和值(流派枚举值)。 您甚至可以使用enumint表示形式作为主键,但我认为这样做没有任何好处。

要使用 EF Core 将enum作为属性存储在数据库中,请使用预定义或内置转换器。

请参阅https://docs.microsoft.com/en-us/ef/core/modeling/value-conversions?tabs=fluent-api#pre-defined-conversions

您需要一个流派枚举和一个流派 class 用于映射:

public enum GenreEnum
{
    Drama,
    Western,
    //...
}

public class Genre
{
    public int Id { get; set; }
    public GenreEnum Name { get; set; }

    // And other properties needed.
}

接着

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Genre>()
        .Property(e => e.Name)
        .HasConversion<string>();
}

这甚至可以通过一个属性更简单地完成:

public enum GenreEnum
{
    Drama,
    Western,
    //...
}

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

    [Column(TypeName = "nvarchar(24)")]
    public GenreEnum Name { get; set; }

    // And other properties needed.
}

当然,您需要一个DbSet<Genre>和一个DbSet<Movie> ,以及MovieGenre之间的多对多关系。

但我不确定我是否会将其用作解决方案。 将来可能需要添加新的流派,一个简单的string而不是enum可能会更好。

编辑

您可以存储一个string ,其中包含某种形式的enum列表的序列化:

例如“西方;戏剧”,或 JSON 表示

可以反序列化它,但这又是丑陋的。

EF 可以很好地与 Enums 一起工作,但我不认为您使用电影流派的示例是一个很好的枚举候选者,因为可以添加新的流派。 SmartEntity 的使用只是一个 class 包装器。

您的流派示例是多对多关系,因此查看数据库方面,您将有如下内容:

Genres
 - GenreId (PK)
 - Name

Series
 - SeriesId (PK)

SeriesGenres
 - SeriesId (PK, FK)
 - GenreId (PK, FK)
 

流派是一个简单的 class,所以说实话,用像 SmartEnum 这样的结构 class 包装它并没有真正的好处。 归根结底,您会希望 EF 像对待任何其他实体一样对待它,以便您可以有效地查询它。 EF Core 5 可以适应多对多关系,而无需定义 SeriesGenre 实体,其中 Series 仅具有 Genre 的集合,然后配置有HasMany(x => x.Genres).WithMany()关系和SeriesGenre 表和 FK 的配置。 EF可以在幕后照顾rest。

枚举的一个更好的例子是状态,您需要一组固定的状态,业务规则逻辑将根据这些状态进行操作,并且除非系统更新以考虑新状态,否则它们不会更改。 例如:

///<summary>
/// Enumeration for order statuses. Ensure this matches the OrderStatuses table.
///</summary>
public enum OrderStatus
{
    None = 0,
    Pending = 1,
    Packing = 2,
    Review = 3,
    Shipped = 4,
    Delivered = 100
}

在这种情况下,订单将记录任何时间点的状态。 业务逻辑将取决于当前状态 state。 我们希望将订单记录存储为状态,但仍要确保我们的数据库具有引用完整性,因此我们将有一个状态表,其中对应的 OrderStatusIds 与枚举中的内容匹配。 然后,Orders 表中的 OrderStatusId 列可以对 OrderStatuses 表具有 FK 约束,以保持数据库中的引用完整性。 OrderStatus 永远不会获得实体声明。

我这样做的主要建议是:

  • 枚举持有表 PK 列不应该使用自增,而是显式的 ID 来匹配 Enum。
  • 类似地,枚举应该对每个值都是明确的,而不是依赖于自动增量。
  • 表和枚举应记录在案以提及它们的相互依赖关系。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM