到目前为止,我的印象是DbContext是用来表示数据库的,因此,如果您的应用程序使用一个数据库,那么您只需要一个DbContext。

然而,一些同事希望将功能区域分解为单独的DbContext类。

我相信这是出于一个好的原因——希望保持代码更干净——但它似乎不稳定。我的直觉告诉我这是个坏主意,但不幸的是,我的直觉并不是设计决策的充分条件。

所以我在寻找:

A)为什么这可能是一个坏主意的具体例子;

B)保证这一切都会顺利解决。


当前回答

提醒:如果你要组合多个上下文,请确保你在各种RealContexts.OnModelCreating()中剪切和粘贴所有功能到你的单个CombinedContext.OnModelCreating()。

我只是浪费时间寻找为什么我的级联删除关系没有被保存,却发现我没有移植modelBuilder.Entity<T>()....WillCascadeOnDelete();代码从我的真实上下文到我的组合上下文。

其他回答

另一点“智慧”。我有一个面向互联网和内部应用程序的数据库。每一个面向都有一个上下文。这有助于我保持纪律严明的隔离。

通过设置默认模式来区分上下文

在EF6中,您可以有多个上下文,只需在DbContext派生类的OnModelCreating方法中指定默认数据库模式的名称(其中有Fluent-API配置)。 这将在EF6工作:

public partial class CustomerModel : DbContext
{   
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema("Customer");

        // Fluent API configuration
    }   
}

本例将使用“Customer”作为数据库表的前缀(而不是“dbo”)。 更重要的是,它还将作为__MigrationHistory表的前缀,例如Customer.__MigrationHistory。 因此,在一个数据库中可以有多个__MigrationHistory表,每个上下文对应一个。 因此,对一个上下文所做的更改不会影响到另一个上下文。

添加迁移时,在add-migration命令中指定配置类的全限定名称(派生自DbMigrationsConfiguration)作为参数:

add-migration NAME_OF_MIGRATION -ConfigurationTypeName FULLY_QUALIFIED_NAME_OF_CONFIGURATION_CLASS

上下文键上的一个简短的单词

根据这篇MSDN文章“章节-多个模型针对同一个数据库”,EF 6可能会处理这种情况,即使只有一个MigrationHistory表存在,因为在表中有一个ContextKey列来区分迁移。

但是,我更喜欢通过指定如上所述的默认模式来拥有多个MigrationHistory表。

使用单独的迁移文件夹

在这种情况下,您可能还想在项目中使用不同的“Migration”文件夹。你可以使用MigrationsDirectory属性设置你的DbMigrationsConfiguration派生类:

internal sealed class ConfigurationA : DbMigrationsConfiguration<ModelA>
{
    public ConfigurationA()
    {
        AutomaticMigrationsEnabled = false;
        MigrationsDirectory = @"Migrations\ModelA";
    }
}

internal sealed class ConfigurationB : DbMigrationsConfiguration<ModelB>
{
    public ConfigurationB()
    {
        AutomaticMigrationsEnabled = false;
        MigrationsDirectory = @"Migrations\ModelB";
    }
}

总结

总而言之,您可以说所有内容都被清晰地分离了:项目中的上下文、迁移文件夹和数据库中的表。

我会选择这样的解决方案,如果有一组实体是一个更大的主题的一部分,但彼此不相关(通过外键)。

如果实体组之间没有任何关联,我会为它们每个创建一个单独的数据库,并在不同的项目中访问它们,可能每个项目中都有一个上下文。

提醒:如果你要组合多个上下文,请确保你在各种RealContexts.OnModelCreating()中剪切和粘贴所有功能到你的单个CombinedContext.OnModelCreating()。

我只是浪费时间寻找为什么我的级联删除关系没有被保存,却发现我没有移植modelBuilder.Entity<T>()....WillCascadeOnDelete();代码从我的真实上下文到我的组合上下文。

首先,在代码中,可以有多个DBContext和一个数据库。您只需在构造函数中指定连接字符串。

public class MovieDBContext : DbContext
{
    public MovieDBContext()
        : base("DefaultConnection")
    {

    }
    public DbSet<Movie> Movies { get; set; }
}

实现以下简单示例:

    ApplicationDbContext forumDB = new ApplicationDbContext();
    MonitorDbContext monitor = new MonitorDbContext();

只在main上下文中设置属性范围:(用于创建和维护DB) 注意:只使用protected:(这里没有显示实体)

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("QAForum", throwIfV1Schema: false)
    {

    }
    protected DbSet<Diagnostic> Diagnostics { get; set; }
    public DbSet<Forum> Forums { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<Thread> Threads { get; set; }
    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    }
}

MonitorContext: 在这里暴露单独的实体

public class MonitorDbContext: DbContext
{
    public MonitorDbContext()
        : base("QAForum")
    {

    }
    public DbSet<Diagnostic> Diagnostics { get; set; }
    // add more here
}

诊断模型:

public class Diagnostic
{
    [Key]
    public Guid DiagnosticID { get; set; }
    public string ApplicationName { get; set; }
    public DateTime DiagnosticTime { get; set; }
    public string Data { get; set; }
}

如果您愿意,可以在主ApplicationDbContext中将所有实体标记为受保护的,然后根据需要为每个模式分离创建额外的上下文。

它们都使用相同的连接字符串,但是它们使用不同的连接,因此不要交叉事务并注意锁定问题。一般来说,你的设计是分离的,所以这种情况不应该发生。