使用实体框架映射数据库的方法?

Posted

技术标签:

【中文标题】使用实体框架映射数据库的方法?【英文标题】:Ways to map database with Entity Framework? 【发布时间】:2020-12-09 20:44:30 【问题描述】:

.NET 中使用实体框架映射数据库有多少种方法?

我知道有代码优先和数据库优先(例如使用.EDMX 向导)。

在数据库优先的上下文中,我可以在不使用.EDMX 的情况下手动映射我的表和关系吗?有多少种方法,你推荐哪一种?

有没有手动表映射的库,哪个最好?

【问题讨论】:

【参考方案1】:

我认为没有最好的方法,但也许有一种方法最适合您的需求。 我将尝试解释您拥有的方式,而不是您可以选择最适合您的方式。

在高层次上,有两种选择:

数据库优先:您定义数据库并使用工具来创建模型类 代码优先:定义类并让 EF 为您管理表

主要是 DB 优先最适合:

映射一个已经存在的数据库:在这种情况下,您的数据库已经设计好了,所以您只需映射实体 您的重点是数据库结构:在这种情况下,最好按照自己的意愿设计数据库,然后使用工具来映射您的实体

当您不介意数据库但想考虑对象模型时,代码优先是最好的选择。当然,您可以使用数据注释或 EF 提供的任何其他方式更改 DB 的生成方式,但您的重点必须是对象模型。

【讨论】:

嗨!如果我的数据库已经创建,是否有映射表和关系的标准?还是有更多方法可以做到? 我从来没有在 .NET core 中使用过 DB,但是在这里你可以找到一些帮助:entityframeworktutorial.net/efcore/…【参考方案2】:

嗨,是的,绝对可以从 EF 映射数据库。它被称为scaffolding。它的作用是为您创建模型和所需文件的数据库。

打开包管理或 cmd 后,您可以键入以下单行代码来支持您的数据库:

CMD:

dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer

包管理器:

 Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer 

在windows官网查看EF Core教程:

https://docs.microsoft.com/en-us/ef/core/managing-schemas/scaffolding?tabs=dotnet-core-cli

对于 EF6,这里有一个很棒的教程:

https://www.illucit.com/en/asp-net/entity-framework-7-code-first-migrations/

【讨论】:

嗨!这适用于标准 .net 吗? 是的,它适用于 EF7:illucit.com/en/asp-net/entity-framework-7-code-first-migrations EF7 是后来成为 EF Core 的旧名称。在 EF6 中,此方案称为“现有数据库的代码优先”docs.microsoft.com/en-us/ef/ef6/modeling/code-first/workflows/… 并且 EF Core 3.1 支持 .NET Framework docs.microsoft.com/en-us/ef/core/miscellaneous/platforms【参考方案3】:

对于数据库优先项目的完全手动控制,您可以利用约定、属性和/或实体配置的组合来配置实体。我发现脚手架在 90% 的情况下都有效,但通常会有生产模式的某些方面,特别是在您无法灵活地更改模式以使其对 ORM 更友好的情况下,脚手架不能完全处理.

另外,如果您正在采用有界上下文(想想具有适合用途的映射的 DbContexts)并希望自定义表/视图映射到实体的方式,那么更明确的映射会有所帮助。例如,对于一般实体,我将映射导航属性,但在我希望获得更大操作的原始性能的情况下,我将希望放弃声明导航属性并严格使用 FK 列。 DbContext 不必担心的“映射”越少,它跟踪的实体越少,它的执行速度就越快。

属性:在这里您声明您的实体类并使用适当的属性来描述表、键和其他方面,例如列重命名等。

[Table("tblOrders", "App")] // tblOrders table in App namespace
public class Order

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int OrderId  get; set; 
    [Column("OrderNum")]
    public string OrderNumber  get; set; 
    public string OrderRef  get; set; 


    [ForeignKey("Customer")]
    public int CustomerId  get; set; 
    public virtual Customer Customer  get; set; 

这适用于您要设置实体的 90-%ile 情况。对于不需要重命名的简单列等,您不需要添加属性并将其保留为约定。

实体配置:通常引用的方法是使用 DbContext 的 OnModelCreating 覆盖并使用modelBuilder 来配置实体。对于具有几个实体的较小系统,这可以管理,但对于较大的系统,这可能会变得相当臃肿,因为一切都以一个方法结束,或者一连串的方法调用将其分解。

protected override void OnModelCreating(DbModelBuilder modelBuilder)

    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<Order>()
        .ToTable("tblOrders", "App")
        .HasKey(x => x.OrderId)
        .Property(x => x.OrderId)
            .HasDatabaseGenerated(DatabaseGeneratedOption.Identity);

    modelBuilder.Entity<Order>()
        .Property(x => x.OrderNumber)
            .HasColumnName("OrderNum);

    modelBuilder.Entity<Order>()
        .HasRequired(x => x.Customer)
        .WithMany(x => x.Orders)
        .HasForeignKey(x => x.CustomerId);
   

记录较少的选项是利用EntityTypeConfigration&lt;TEntity&gt;(EF Core 中的IEntityTypeConfiguration&lt;TEntity&gt;

public class OrderConfiguration : EntityTypeConfiguration<Order>

    public OrderConfiguration()
    
        ToTable("tblOrders", "App");
        HasKey(x => x.OrderId)
            .Property(x => x.OrderId)
            .HasDatabaseGenerated(DatabaseGeneratedOption.Identity);

        Property(x => x.OrderNumber)
            .HasColumnName("OrderNum");

        HasRequired(x => x.Customer)
            .WithMany(x => x.Orders)
            .HasForeignKey(x => x.CustomerId);
    

       

从那里只需要初始化 DbContext 以加载实体类型配置。这是在 OnModelCreating 中完成的,您可以显式执行此操作,或通过程序集添加所有配置。

modelBuilder.Configurations.AddFromAssembly(GetType().Assembly);

就个人而言,我默认为所有实体声明 EntityTypeConfigurations,因为我更喜欢尽可能少地依赖约定。明确的配置意味着您可以调查和处理某些约定无法按您期望的方式工作的地方,并且它允许您为诸如 ForeignKeys 之类的东西声明映射,而无需在实体中声明 FK 属性。 (强烈建议避免关系的两个真相来源,即 FK 和导航属性)

我的项目通常会有一个 .Data 项目,我将在其中保留项目的实体、DbContext 和存储库。我放置在 /Entities/Configuration 下的 EntityTypeConfiguration 实例。它们可以像实体类本身的内部成员一样容易地存放在实体类文件中,或者嵌套在实体类下。 (即使用 NestIn 之类的插件)

【讨论】:

以上是关于使用实体框架映射数据库的方法?的主要内容,如果未能解决你的问题,请参考以下文章

调试实体框架 DBContext API 映射

实体框架数据集映射

使用实体框架 Fluent Api 映射 System.Uri

领域模型和实体框架之间的存储库模式和映射

更新映射到视图的实体框架实体

实体框架映射问题