如何在 EntityFramework Core 中使用部分 class 和部分 OnModelCreating 方法扩展 DbContext
How to extend DbContext with partial class and partial OnModelCreating method in EntityFramework Core
我正在使用 EF Core 和 DatabaseFirst 方法。我的 dbContext 是由 Scaffold-DbContext
命令自动创建的。
我需要将一些新的 DbSet 添加到 dbContext 中,并向 OnModelCreating
方法中添加一些额外的代码,但是在每次添加代码的脚手架之后,我都必须再次添加它。
我想做的是创建另一个部分 dbContext class 并将 protected override void OnModelCreating(ModelBuilder modelBuilder)
方法标记为部分
但出现错误:
A partial method cannot have access modifiers or the virtual, abstract, override, new, sealed, or extern modifiers.
A partial method may not have multiple implementing declarations
这是一个伪代码:
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);
});
}
}
您不能覆盖部分 class 中的方法,因为所有 "parts" 都变成一个 class。但是您可以通过让主 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);
}
}
另一种方法是创建另一个上下文 class,它继承自 MyDbContext,实际上包含所有自定义代码。然后使用这个新的 class 作为您的上下文。这样就不需要更新生成的代码了。
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);
});
}
}
EFCore 3 - 他们最终 解决了这个问题!
您现在可以像这样在部分 class 中实施 OnModelCreatingPartial
。注意 partial
keyword on both the class and method:
public partial class RRStoreContext : DbContext
{
partial void OnModelCreatingPartial(ModelBuilder builder)
{
builder.Entity<RepeatOrderSummaryView>().HasNoKey();
}
}
如果您查看生成的上下文文件 - 在 OnModelCreating(...)
的最后您会看到...
OnModelCreatingPartial(modelBuilder);
注意:我使用脚手架,但我需要为存储过程手动添加 HasNoKey
(使用自定义 return 类型,否则没有脚手架)。
部分 classes 的目的是您可以创建另一个具有相同名称的部分 class。您可以在此处利用部分 class 优势。
创建另一个 class 与“MyDbContext”同名,但设置不同的文件名,例如"MyCustomDbContext".
public partial class MyDbContext
{
partial void OnModelCreatingPartial(ModelBuilder modelBuilder){
// Right your custom code here
}
}
现在,无论何时您再次生成模型,它都不会重写您的自定义上下文 class。
可以通过以下方式使用部分方法:
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!
}
}
当然,以上要求您为生成的分部方法生成 'template'(如以上两种工具所提供的)。否则,您需要控制代码并能够在生成的 class.
中调整几行代码
关于如何使用部分方法的更多信息:
我正在使用 EF Core 和 DatabaseFirst 方法。我的 dbContext 是由 Scaffold-DbContext
命令自动创建的。
我需要将一些新的 DbSet 添加到 dbContext 中,并向 OnModelCreating
方法中添加一些额外的代码,但是在每次添加代码的脚手架之后,我都必须再次添加它。
我想做的是创建另一个部分 dbContext class 并将 protected override void OnModelCreating(ModelBuilder modelBuilder)
方法标记为部分
但出现错误:
A partial method cannot have access modifiers or the virtual, abstract, override, new, sealed, or extern modifiers.
A partial method may not have multiple implementing declarations
这是一个伪代码:
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);
});
}
}
您不能覆盖部分 class 中的方法,因为所有 "parts" 都变成一个 class。但是您可以通过让主 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);
}
}
另一种方法是创建另一个上下文 class,它继承自 MyDbContext,实际上包含所有自定义代码。然后使用这个新的 class 作为您的上下文。这样就不需要更新生成的代码了。
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);
});
}
}
EFCore 3 - 他们最终 解决了这个问题!
您现在可以像这样在部分 class 中实施 OnModelCreatingPartial
。注意 partial
keyword on both the class and method:
public partial class RRStoreContext : DbContext
{
partial void OnModelCreatingPartial(ModelBuilder builder)
{
builder.Entity<RepeatOrderSummaryView>().HasNoKey();
}
}
如果您查看生成的上下文文件 - 在 OnModelCreating(...)
的最后您会看到...
OnModelCreatingPartial(modelBuilder);
注意:我使用脚手架,但我需要为存储过程手动添加 HasNoKey
(使用自定义 return 类型,否则没有脚手架)。
部分 classes 的目的是您可以创建另一个具有相同名称的部分 class。您可以在此处利用部分 class 优势。
创建另一个 class 与“MyDbContext”同名,但设置不同的文件名,例如"MyCustomDbContext".
public partial class MyDbContext
{
partial void OnModelCreatingPartial(ModelBuilder modelBuilder){
// Right your custom code here
}
}
现在,无论何时您再次生成模型,它都不会重写您的自定义上下文 class。
可以通过以下方式使用部分方法:
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!
}
}
当然,以上要求您为生成的分部方法生成 'template'(如以上两种工具所提供的)。否则,您需要控制代码并能够在生成的 class.
中调整几行代码关于如何使用部分方法的更多信息: