Entity Framework Core - 枚举脚手架生成

5

背景:

我使用基于数据库的方法使用 Entity Framework Core 生成实体,并使用 Scaffolding。每当我更改数据库中的内容时,我都会使用 -f 参数运行 Scaffolding 来重写生成的实体。到目前为止都很好。在我的数据库架构中,我有一些查找表,它们作为其他表的枚举类型,并且这些其他表在其上具有外键。

问题:

我想从这些查找表中生成可以在我的代码中使用的枚举类型。这些枚举类型应由查找表中的数据填充(Id、Value)。这种情况是否可能?

我看到可以忽略这些表格的实体生成,并使用 值转换 将自己的枚举类型与其链接。但这真的是唯一的解决方法吗?


我的数据库架构示例:

TABLE: Category

Id Value
0 Cardio
1 Strength
2 Hyperthrophy

TABLE: Exercise

Id Name Category
0 Deadlift 1
1 Benchpress 1
2 Jogging 0

所以,从表格 Category 中,我想生成简单的枚举类型:

public enum Category {
    Cardio = 0,
    Strength = 1,
    Hyperthrophy = 2
}

然后我希望它可以在实体Exercise中使用,例如:
public partial class Exercise {
    public Exercise() {
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public Category Category { get; set; }
}

1
@ISR5 不是这样的,相反的。 - JHBonarius
没有工具可以通过检查表模式或值来猜测数字列实际上是一个封闭的值集合,即枚举。只有数据库产品本身支持它们,才有意义生成枚举。虽然PostgreSQL和MySQL有字符串枚举类型,但SQL Server没有枚举。 - Panagiotis Kanavos
@panagiotis-kanavos 当然,如果使用的数据库不支持,那么没有工具可以猜测。但是有没有一种方法告诉脚手架需要这样的转换呢?例如通过覆盖 OnConfiguringOnModelCreating 并指定该表及其内容应表示为枚举来实现? - ssamko
那将是什么枚举,它的值和标签是什么?即使您可以告诉工具特定列是“枚举”,您仍然需要手动输入标签。PostgreSQL和MySQL确实有枚举,而NpgSql将PostgreSQL枚举映射到C#枚举,但即使在那里,脚手架也只会添加映射。您仍然需要自己创建枚举。 - Panagiotis Kanavos
在支持枚举的数据库中,枚举的脚手架由数据库提供者负责。但是 SQL Server 并不支持枚举,因此 SQL Server 提供程序也不会这样做。您可能可以创建一个扩展来修改 OnModelCreating,但您还必须在命令行中指定这些列。您仍然需要自己创建枚举。 - Panagiotis Kanavos
显示剩余2条评论
2个回答

1
尽管理论上可以根据任何数据生成代码,但我不知道目前有什么工具可以满足您的要求。
但真正的问题是:为什么您想要这样做?或者更好的问题是,这确实是您想要的吗?
脚手架是基于数据库模式而非表内容的。表数据应该被认为是动态的。否则(即如果数据是静态的),您应该质疑为什么要将其放入数据库中:您可以并且应该将其放入代码中。枚举是一种相当静态的结构。
Entity Framework是用于关系型数据库的对象映射器。因此,您应该只使用动态关系和键耦合。

表格数据应被视为动态的。-我不这么认为。例如,如果您有一个名为“状态”的表格,其中包含几个选项,如“已创建”,“进行中”,“测试中”和“已关闭”,以及使用此状态的“工单”表格,则具有固定/静态选项的表格旨在用作外键。您只需将其用于保持“工单”表格中值的规范化,并防止在那里编写其他值(在“TicketStatus”列中)。如果我理解正确。 - ssamko
1
@ssamko 我会反对这个观点,因为它并不是真正的静态。你可以随时添加或删除一行。因此,既然将表格视为“静态”是你的设计和选择,那么在代码中正确映射它就是你的责任。 - JHBonarius
2
@ssamko 实际上,自动脚手架更多地是一个“初学者”/“快速入门”的功能。一旦你开始做实际的复杂应用程序,它很快就会不够用了。 - JHBonarius
1
PostgreSQL和MySQL都有字符串枚举类型。NpgSQL支持它们,但是脚手架似乎很棘手。映射将被生成,但不包括C#枚举:未来可能会有可能脚手架实际的枚举类型(以及属性),但目前还没有这种情况发生。 - Panagiotis Kanavos

0

这不是不可能,但你需要知道它是否值得。我使用数据库优先开发,因此为了生成实体,我总是运行脚手架工具。当我需要自定义我的实体时,我会重写该工具用于生成文件的方法。

请参阅:

[SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "<Pending>")]
public class EntityTypeGenerator : CSharpEntityTypeGenerator
{

    public EntityTypeGenerator([NotNull] IAnnotationCodeGenerator annotationCodeGenerator,
          [NotNull] ICSharpHelper cSharpHelper) :
          base(annotationCodeGenerator, cSharpHelper)
    {
    }

    public override string WriteCode(IEntityType entityType,
           string @namespace,
           bool useDataAnnotations,
           bool useNullableReferenceTypes)
    {
        var code = base.WriteCode(entityType, @namespace,
                    useDataAnnotations, useNullableReferenceTypes);

        var oldString = "public partial class " + entityType.Name;
        var newString = "public partial class " + entityType.Name + ":
                             Repositories.Infra.EntityBase";

        var newCode = code.Replace(oldString, newString);

        if (entityType.Name == "Task")
        {
            oldString = "byte StatusId ";
            newString = "Business.Models.Tarefas.EnumStatusTask StatusId ";
            newCode = code.Replace(oldString, newString);
        }

        return newCode;
    }

}

为了使其工作,我创建了一个专门用于影响实体生成的独立项目。在其中,我引用了 Microsoft.EntityFrameworkCore.Design 库。

enter image description here

我将我的生成器类注入到DesignTimeServices类的实现中

public class DesignTimeServices: IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection serviceCollection)
    {
        serviceCollection.AddSingleton<ICSharpEntityTypeGenerator, EntityTypeGenerator>();
    }
}

在主项目中(运行时项目,本例中为API),我引用了我的新项目,并添加了对Microsoft.EntityFrameworkCore.Tools库的引用。

teste

以下链接可以作为理解它的工作原理以及您可以做什么的基础https://learn.microsoft.com/en-us/ef/core/cli/services


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接