如何在 EntityFramework Core 中使用部分类和部分 OnModelCreating 方法扩展 DbContext

Posted

技术标签:

【中文标题】如何在 EntityFramework Core 中使用部分类和部分 OnModelCreating 方法扩展 DbContext【英文标题】:How to extend DbContext with partial class and partial OnModelCreating method in EntityFramework Core 【发布时间】:2019-02-10 10:00:12 【问题描述】:

我正在使用 EF Core 和 DatabaseFirst 方法。我的 dbContext 是由Scaffold-DbContext 命令自动创建的。

我需要在 dbContext 中添加一些新的 DbSet,并在 OnModelCreating 方法中添加一些额外的代码,但是在每个脚手架之后,添加的代码都会被删除,我必须每次都再次添加。

我要做的是创建另一个部分 dbContext 类并将protected override void OnModelCreating(ModelBuilder modelBuilder) 方法标记为部分

但得到错误:

部分方法不能有访问修饰符或 virtual、abstract、override、new、sealed 或 extern 修饰符。

一个分部方法不能有多个实现声明

这是一个伪代码:

MyDbContext1.cs - 由Scaffold-DbContext生成

public partial class MyDbContext : DbContext

    public MyDbContext()
    
    

    public MyDbContext(DbContextOptions<MyDbContext> options)
        : base(options)
    
    

    public virtual DbSet<Client> Clients  get; set; 

    protected override partial void OnModelCreating(ModelBuilder modelBuilder)
    
        modelBuilder.Entity<Client>(entity =>
        
            // some code ...
        
    

MyDbContext2.cs - 我每次在搭建脚手架后将这段代码添加到 dbContext 中:

public partial class MyDbContext

    public virtual DbSet<JustAnotherEntity> AnotherEntity  get; set; 

    protected override partial void OnModelCreating(ModelBuilder modelBuilder)
    
        modelBuilder.Entity<JustAnotherEntity>(entity =>
        
            entity.HasKey(e => new e.Id, e.IdAction, e.IdState)
                .ForSqlServerIsClustered(false);
        );
    

【问题讨论】:

类似于this 的帖子。无法通过partial 拆分方法逻辑。应该先执行哪个方法,或者编译器应该如何知道,如何合并部分方法?来自microsoft docs:A partial method declaration consists of two parts: the definition, and the implementation. 1/2 您必须从您的方法声明中删除partial,并将您的逻辑放在您的一个类中。 2/2 脚手架代码是硬编码的,没有扩展点。没有机会。 EF Core Power Tools 为您完成这项工作 【参考方案1】:

EFCore 3 - 他们终于修复了这个问题!

您现在可以像这样在部分类中实现OnModelCreatingPartial。请注意class and method 上的partial 关键字:

public partial class RRStoreContext : DbContext

    partial void OnModelCreatingPartial(ModelBuilder builder)
    
        builder.Entity<RepeatOrderSummaryView>().HasNoKey();
    

如果您查看生成的上下文文件 - 就在 OnModelCreating(...) 的最后,您会看到...

 OnModelCreatingPartial(modelBuilder);

注意:我使用脚手架,但我需要为存储过程手动添加 HasNoKey(具有未以其他方式搭建的自定义返回类型)。

【讨论】:

知道在哪里可以找到有关此 OnModelCreatingPartial 方法的任何官方文档或我们应该如何使用它吗?我的意思是我可以冒险猜测,但我无法在任何地方找到它。 @SimonGymer 这个问题是谷歌最热门的比赛,我也找不到!这是一篇博客文章虽然irina.codes/extending-ef-core-dbcontext @Simon_Weaver 这个官方怎么样。这是一个自定义实现,看起来像 @Emil 我不太清楚你的意思。 “官方”部分是生成的代码(由官方脚手架)现在调用OnModelCreatingPartial(...)(如果您已定义它)。这比以前容易得多。上面显示的代码是您添加到生成的代码所需要做的所有事情。您始终能够修改脚手架代码,但这允许您重新生成脚手架代码,而不会干扰您可能所做的更改。【参考方案2】:

另一种方法是创建另一个从 MyDbContext 继承的上下文类,该类实际上包含所有自定义代码。然后使用这个新类作为你的上下文。这样就不需要更新生成的代码了。

public class MyDbContext2 : MyDbContext 

    public MyDbContext2()
    
    

    public MyDbContext2(DbContextOptions<MyDbContext> options)
        : base(options)
    
    

    public virtual DbSet<JustAnotherEntity> AnotherEntity  get; set; 

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<JustAnotherEntity>(entity =>
        
            entity.HasKey(e => new e.Id, e.IdAction, e.IdState)
                .ForSqlServerIsClustered(false);
        );
    

【讨论】:

比公认的答案要好得多。基类支架无需任何手动更改。 我已将此解决方案标记为正确答案,因为在搭建脚手架后确实不需要更改 MyDbContext 中的任何内容。 如何在 MVC4 和实体框架 6 中做到这一点。如下代码所示,这只适用于实体核心.. public MyDbContext2(DbContextOptions options) : base(options) 刚刚在 EF Core 3 项目中执行此操作以扩展自动生成的类。谢谢你。最佳答案。完美的答案。 ;)【参考方案3】:

您不能覆盖部分类中的方法,因为所有“部分”都变成了一个类。但是您可以通过让主 OnModelCreating 调用 partial method 来完成此操作。像这样:

public partial class Db : DbContext

    partial void OnModelCreating2(ModelBuilder modelBuilder)
    
       //additional config
    


public partial class Db : DbContext


    public DbSet<Person> Persons  get; set; 

    partial void OnModelCreating2(ModelBuilder modelBuilder);
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    
        base.OnModelCreating(modelBuilder);

        OnModelCreating2(modelBuilder);
    
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    
        optionsBuilder.UseSqlServer("Server=localhost;database=efcore2test;integrated security=true");
        base.OnConfiguring(optionsBuilder);
    

【讨论】:

这只会让事情变得更糟:OnModelCreating2(modelBuilder); 调用不会生成上下文,因此他们仍然必须不断修改生成的代码。如果脚手架代码是可扩展的,例如基于可编辑的 tt 模板,这将是一个选项。 很好的解决方法,但仍需要添加这些行 OnModelCreating2(ModelBuilder modelBuilder); OnModelCreating2(modelBuilder); @GertArnold 可能是这样的***.com/a/48152710/492482【参考方案4】:

部分类的目的是您可以创建另一个具有相同名称的部分类。您可以在此处利用部分类的好处。

创建另一个与“MyDbContext”同名但文件名不同的类,例如“MyCustomDbContext”。

public partial class MyDbContext

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
        // Right your custom code here
    

现在,无论您何时再次生成模型,它都不会重写您的自定义上下文类。

【讨论】:

【参考方案5】:

可以通过以下方式使用部分方法:

public partial class MyDbContext : DbContext

    public MyDbContext()
    
    

    public MyDbContext(DbContextOptions<MyDbContext> options)
        : base(options)
    
    

    ...

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    
        OnModelCreatingPartial(modelBuilder);
    

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);

EF Core Power Tools 和更高版本的 EF Core(在我的例子中是 EF Core 版本 6)都会生成此设置。

https://marketplace.visualstudio.com/items?itemName=ErikEJ.EFCorePowerTools

https://docs.microsoft.com/en-us/ef/core/get-started/overview/install

鉴于自动生成的 DbContext 准备了一个未完全实现的方法,您可以自己在另一个文件的其他地方轻松实现它:

public partial class MyDbContext : DbContext

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
    
        // Your own stuff here!
    

当然,以上要求您为生成的部分方法提供“模板”(正如上述两个工具所提供的那样)。否则,您需要控制代码并能够在生成的类中调整几行代码。

有关如何使用部分方法的更多信息:

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/partial-classes-and-methods#partial-methods

【讨论】:

以上是关于如何在 EntityFramework Core 中使用部分类和部分 OnModelCreating 方法扩展 DbContext的主要内容,如果未能解决你的问题,请参考以下文章

使用 Entityframework Core,如何在不更改连接字符串的情况下动态更改我连接的 MySql 数据库?

EntityFramework 7 更名为EntityFramework Core(预发布状态)

第15章 使用EntityFramework Core进行配置和操作数据 I

如何在 .NET Core 3.0 Entity Framework 中执行组加入?

EntityFramework.dll 中出现“System.Data.Entity.Core.MappingException”类型的异常,但未在用户代码中处理

EntityFramework Core解决并发详解