使用Mehdime.Entity AmbientDbContextLocator实例化DbContext派生类

时间:2015-11-10 03:32:58

标签: ef-code-first ninject mehdime-entity

谁能告诉我我做错了什么? 我想使用https://www.nuget.org/packages/Mehdime.Entity中的Mehdime.Entity来管理控制台应用程序中的DBContext派生类。我也在使用NInject。

我的DBContext派生类的连接字符串部分是从标准app.config ConnectionStrings生成的,也是通过命令行参数(在我的控制台应用程序中)进入的AppDomain值生成的。

我的DBContext派生类使用程序实现的类来编写连接字符串,该类考虑了命令行参数,如下所示:

public class TaskManagementDbContext : DbContext
{
    public TaskManagementDbContext(IConnectionStringResolver csr) :
        base(csr.GetConnectionString("Default"))
    {
    }
}

IConnectionStringResolver基本上实现GetConnectionString(),它通过使用给定的命名标准app.config ConnectionString和命令行参数来返回连接字符串。

当我使用NInject直接实例化DbContext但在尝试与Mehdime.Entity一起使用时,这是正常的,它正在进行实例化AmbientDbContextLocator并抛出MissingMethodException,因为它要求我的DBContext派生类具有无参数构造函数:

public class TaskRepository : ITaskRepository
{
    private readonly IAmbientDbContextLocator _ambientDbContextLocator;

    private TaskManagementDbContext DbContext
    {
        get
        {
            // MissingMethodException thrown "No parameterless constructor defined for this object"
            var dbContext = _ambientDbContextLocator.Get<TaskManagementDbContext>();
            ...
        }
    }

在这种情况下,如何在运行时向我的DBContext派生类提供连接字符串?我怀疑我的方式是错误的。感谢。

1 个答案:

答案 0 :(得分:2)

行。我已经找到了解决方案,我将这个问题放在这里给其他人:

  1. 创建自己的IDbContextFactory实现(见下文)。我将它放在与我的数据访问层(即我的DbContexts)相同的类库中。你将在我的例子中看到我如何“寻找”一个特定的构造函数原型(在我的例子中,类型为IDbContextFactory的1个参数 - 你的无疑会有所不同)。如果找到,请获取实际参数并调用DBContext派生类的新实例。如果没有找到,你可以抛出异常,或者在我的情况下,尝试调用默认构造函数(如果存在)。
  2. 代码:

    using System;
    using System.Data.Entity;
    using Mehdime.Entity;
    using Ninject;
    using TaskProcessor.Common;
    
    namespace TaskProcessor.Data.Connection
    {
        public class DbContextWithCSRFactory : IDbContextFactory
        {
            public TDbContext CreateDbContext<TDbContext>() where TDbContext : DbContext
            {
                // Try to locate a constuctor with a single IConnectionStringResolver parameter...
                var ci = typeof(TDbContext).GetConstructor(new[] { typeof(IConnectionStringResolver) });
                if(ci != null)
                {
                    // Call it with the actual parameter
                    var param1 = GlobalKernel.Instance.Get<IConnectionStringResolver>();
                    return (TDbContext)ci.Invoke(new object[] { param1 });
                }
    
                // Call parameterless constuctor instead (this is the default of what DbContextScope does)
                return (TDbContext)Activator.CreateInstance<TDbContext>();
            }
        }
    }
    
    1. 在NInject中创建一个绑定,以便调用IDbContextFactory实现:
    2. 代码:

      private void AddBindings(IKernel kernel)
      {   ...
          kernel.Bind<IDbContextFactory>().To<Data.Connection.DbContextWithCSRFactory>().InSingletonScope();
      }
      

      现在一切都已到位。