从另一个项目扩展 DbContext

Posted

技术标签:

【中文标题】从另一个项目扩展 DbContext【英文标题】:Extending DbContext from another project 【发布时间】:2017-01-12 00:37:04 【问题描述】:

我正在尝试通过我正在处理的项目实现一些层分离。我的想法是我可以采用网站的任何功能并对其进行修改。例如,如果您使用诸如新闻之类的内容并且希望将功能添加到网站,那么在代码中您只需要导入新闻服务和模型、数据层等。所有这些都将被导入。

请注意,我使用 Ninject 作为项目的一部分来注入依赖项,因此我不需要引用具体的类,我只引用合约。

我有我的主要项目和数据层:

public class MainDbContext : CustomIdentityDbContext, IMainDbContext



如您所见,它扩展了 CustomIdentityDbContext,如下所示:

public class CustomIdentityDbContext : IdentityDbContext<CustomUser>, ICustomIdentityDbContext

    public CustomIdentityDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    
    

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaim");
        modelBuilder.Entity<IdentityUserRole>().ToTable("UserRole");
        modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogin");
        modelBuilder.Entity<IdentityRole>().ToTable("Role");
        modelBuilder.Entity<AzularisUser>().ToTable("User");
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
    

    public static DbContext Create()
    
        return new CustomIdentityDbContext();
    

我的问题是我需要一个 News 表,然后我需要 EF6 来映射该表,就像它为 Identity 所做的那样。我想不通的是如何建立这种关系。如何将DbSet&lt;News&gt; News get; set; 添加到我的 MainDbContext 中,而无需在其中写入该行并引用 News 对象。因此,我试图在我引用我的服务时将其动态添加到我的 MainDbContext 类中,因为该服务将触发所有其他类通过 ninject 和绑定创建自己。

换句话说,新闻的数据层需要将自己注入到 MainDbContext 中,而 MainDbContext 在其引用中不知道它。这样的事情可能吗?如果是这样,我将如何实现它?

这是我尝试过的:

public class NewsDbContext : DbContext, INewsDbContext

    public DbSet<News> News  get; set; 
    public NewsDbContext() : base("DefaultConnection")  

    public IEnumerable<INews> QueryNews()
    
        return News;
    

上面的代码编译并运行,但是,它没有创建一个表,当我尝试查询它或插入一条记录时,它会因为表不存在而中断。我不太确定如何做到这一点,而且我非常没有想法。这样的事情可能吗?

编辑:

我意识到我可能没有正确解释自己。让我再尝试一次。我有一个多层结构。我有一个服务、数据、域和 DTO 层。这 4 层组成了一个插件。在这 4 层之上,我还有 4 层是这些层的接口,也就是契约。我使用 Ninject 将我的合约绑定到实现层,这样主项目就不会真正引用项目中的实现层。出于这个原因,我试图将数据层插入主项目的数据层,而主项目数据层实际上没有引用插件的数据层。问题是插件将有自己需要的表。我希望在第一次运行项目时使用 EF6 自动创建这些表。

我的主项目也以与插件相同的方式拆分,它有所有 4 层,外加一个管理器层。管理器是服务的集合,没有其他用途,它只是在 Ninject 的帮助下根据合同实例化它们。项目的核心包含所有视图、脚本和 css 文件,但它引用了管理器的界面。使用ninject,我创建了一个管理器实例。经理再次拥有对合同的所有引用,并使用 ninject 创建这些合同的实例。服务引用数据层的合约,数据层将查询信息并将结果带回服务,该服务将传递回控制器。我希望这能更好地解释我的结构。通过这种方法,我试图创建一个真正的模块化项目,您可以在其中交换 dll 的实现并让项目继续工作,而无需重新编译整个该死的东西。我可以在 2 个 dll 上拥有两个完全独立的功能,但只要它们实现相同的合同,无论其文件夹中有哪个 dll,网站都应该可以工作。

我刚才描述的所有内容都可以使用,除了使其与 EF6 一起使用。我有一个与 DAPPER 非常相似的结构,当你编写自己的查询时,它都很好而且很漂亮,所以我没有任何问题。我正在尝试使用 EF6 复制它。再次,我的问题是,我如何让 EF6 创建表,当唯一被引用的是服务接口时,我如何动态添加它们。也许界面可以有一个 MapTables 功能,但我又不确定如何完成对 EF6 的动态添加。

我有一个想法,但我不确定这是否可行,也不知道该怎么做,但是如果我将 DB 上下文作为类型传递而不是扩展它会怎样?

【问题讨论】:

通常情况下,应该让NewsDbContext 成为CustomIdentityDbContext 的子类。但是,如果我对您的理解正确,您希望包含 News 的程序集独立于“基础”程序集。换句话说,Web 应用程序应该能够导入基础程序集和任何其他程序集,并且它们应该以某种方式合并到一个数据层中。对吗? @GertArnold 是的,我希望将它们合并到一个数据层中。 Web App 应该可以通过服务导入新闻程序集并使用它。 最大的问题是:(哪个程序集)知道哪些类应该是实体框架类模型的一部分? @GertArnold 主项目应该了解该服务,并且通过了解该服务,数据层需要以某种方式合并。 @GertArnold 我更新了我的问题,并试图更好地解释它。 【参考方案1】:

我已经部分解决了我的问题。一旦我有一个完整的解决方案,我将把它作为答案发布并更新。到目前为止,我已经学会了如何生成我的表格。它在主项目的 DB Context 中包含以下代码:

protected override void OnModelCreating(DbModelBuilder modelBuilder)

    var entityMethod = typeof(DbModelBuilder).GetMethod("Entity");

    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    
        var entityTypes = assembly
          .GetTypes()
          .Where(t =>
            t.GetCustomAttributes(typeof(PersistentAttribute), inherit: true)
            .Any());

        foreach (var type in entityTypes)
        
            entityMethod.MakeGenericMethod(type)
              .Invoke(modelBuilder, new object[]  );
        
    

    base.OnModelCreating(modelBuilder);

以上代码将确保为添加了“PersistentAttribute”的任何类创建表。我的下一个问题是尝试从外部 DLL 查询。因此,新闻项目的数据层需要能够通过以某种方式传递在主项目中创建的上下文来查询自身。感谢ninject,我对此几乎没有什么想法,一旦我弄清楚了,我会发布更多。

【讨论】:

您好,您找到解决方案了吗? 不使用 EF。我最终改用 Dapper,效果更好。【参考方案2】:

试着把你的 NewsDbContext 改成这样:

public class NewsDbContext  : DbContext

    public NewsDbContext (DbContextOptions<NewsDbContext  options) : base(options)  

    public virtual DbSet<News> News get; set; 




public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>

    public ApplicationDbContext CreateDbContext(string[] args)
    
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile(@Directory.GetCurrentDirectory() + "/../SolutionName/appsettings.json")
            .Build();
        var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
        var connectionString = configuration.GetConnectionString("YourDbConnectionName");
        builder.UseSqlServer(connectionString);
        return new ApplicationDbContext(builder.Options);
    

要解析SetBasePath,请添加Microsoft.Extensions.Configuration.FileExtensions 包,要解析AddJsonFile,请添加对Microsoft.Extensions.Configuration.Json 包的引用。

【讨论】:

以上是关于从另一个项目扩展 DbContext的主要内容,如果未能解决你的问题,请参考以下文章

从另一个 .storyboard 扩展 MyViewController

从另一个扩展部分渲染 TYPO3 Fluid

从另一个类重置扩展文件 userdefualt

从另一个vscode扩展添加到vscode python jedi的路径

Java:从另一个类扩展侦听器方法的功能

如何使泛型 TypeScript 接口从另一个泛型接口扩展?