不带无参数 DbContext 和 DbContextFactory 构造函数的 Add-Migration

2024-01-28

我的应用程序没有无参数构造函数DbContext实现,我不喜欢提供无参数构造函数IDbContextFactory<>执行。

原因是我想控制 DbContext 指向的位置。这就是为什么我的所有构造函数都会请求 ConnectionString Provider。

public class MyDbContext : DbContext
{
    internal MyDbContext(IConnectionStringProvider provider) : base(provider.ConnectionString) {}
}

and

public class MyContextFactory : IDbContextFactory<MyDbContext>
{
    private readonly IConnectionStringProvider _provider;
    public MyContextFactory(IConnectionStringProvider provider)
    {
        _provider = provider;
    }
    public MyDbContext Create()
    {
        return new MyDbContext(_provider.ConnectionString);
    }
}

我绝对不想添加默认构造函数!我已经这样做了,并且由于错误的 App.config 中的错误连接字符串或假设默认连接字符串(如默认构造函数)而在生产中崩溃DbContext做。我想使用相同的基础设施

  • 调试/发布(并且仅注入不同的IConnectionStringProvider)
  • Calling Add-Migration script
  • Running DbMigrator.GetPendingMigrations()

目前我收到了其中一些消息:

上下文工厂类型“Test.MyContextFactory”没有公共无参数构造函数。添加公共无参数构造函数,在上下文程序集中创建 IDbContextFactory 实现,或者使用 DbConfiguration 注册上下文工厂。

- -更新 - -

这可能是重复的如何将连接字符串注入 IDbContextFactory 的实例中? https://stackoverflow.com/questions/18734496但它没有解决方案。我解释一下原因:

  • I always use Add-Migration with connection string, so how can I provide a DbContext or IDbContextFactory<> that consumes it? Instead of parameterless constructors?

    添加迁移 MyMigration -ConnectionStringName“MyConnectionString”

  • 同样的问题在这里:我使用DbMigrator.GetPendingMigrations()这也要求无参数DbContext or IDbContextFactory<>实施。

据我了解 EntityFramework 违反了封装通过暗示默认构造函数 http://blog.ploeh.dk/2011/05/30/DesignSmellDefaultConstructor和原因时间耦合 http://blog.ploeh.dk/2011/05/24/DesignSmellTemporalCoupling/这不是万无一失的。所以请提出一个没有无参数构造函数的解决方案。


我总是用Add-Migration带有连接字符串,那么我如何提供DbContext or IDbContextFactory<>那会消耗它吗?而不是无参数构造函数?

花了一些时间对实体框架进行逆向工程后,结果证明答案是:你不能!

这是你跑步时会发生的事情Add-Migration(没有默认构造函数):

System.Data.Entity.Migrations.Infrastructure.MigrationsException: The target context 'Namespace.MyContext' is not constructible. Add a default constructor or provide an implementation of IDbContextFactory.
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext, DatabaseExistenceState existenceState, Boolean calledByCreateDatabase)
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
   at System.Data.Entity.Migrations.Design.MigrationScaffolder..ctor(DbMigrationsConfiguration migrationsConfiguration)
   at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.RunCore()
   at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()

让我们来看看DbMigrator构造函数。当从Add-Migration命令,usersContext一片空白,configuration.TargetDatabase is notnull 并包含从命令行参数传递的信息,例如-ConnectionStringName, -ConnectionString and -ConnectionProviderName. So new DbContextInfo(configuration.ContextType, configuration.TargetDatabase)叫做。

internal DbMigrator(DbMigrationsConfiguration configuration, DbContext usersContext, DatabaseExistenceState existenceState, bool calledByCreateDatabase) : base(null)
{
    Check.NotNull(configuration, "configuration");
    Check.NotNull(configuration.ContextType, "configuration.ContextType");
    _configuration = configuration;
    _calledByCreateDatabase = calledByCreateDatabase;
    _existenceState = existenceState;
    if (usersContext != null)
    {
        _usersContextInfo = new DbContextInfo(usersContext);
    }
    else
    {
        _usersContextInfo = ((configuration.TargetDatabase == null) ?
            new DbContextInfo(configuration.ContextType) :
            new DbContextInfo(configuration.ContextType, configuration.TargetDatabase));
        if (!_usersContextInfo.IsConstructible)
        {
            throw Error.ContextNotConstructible(configuration.ContextType);
        }
    }
    // ...
}

For the DbMigrator不扔,DbContextInfo实例必须是可构造的。现在,让我们看看DbContextInfo构造函数。为了DbContextInfo是可建造的,两者CreateActivator() and CreateInstance()不得返回 null。

private DbContextInfo(Type contextType, DbProviderInfo modelProviderInfo, AppConfig config, DbConnectionInfo connectionInfo, Func<IDbDependencyResolver> resolver = null)
{
    _resolver = (resolver ?? ((Func<IDbDependencyResolver>)(() => DbConfiguration.DependencyResolver)));
    _contextType = contextType;
    _modelProviderInfo = modelProviderInfo;
    _appConfig = config;
    _connectionInfo = connectionInfo;
    _activator = CreateActivator();
    if (_activator != null)
    {
        DbContext dbContext = CreateInstance();
        if (dbContext != null)
        {
            _isConstructible = true;
            using (dbContext)
            {
                _connectionString = DbInterception.Dispatch.Connection.GetConnectionString(dbContext.InternalContext.Connection, new DbInterceptionContext().WithDbContext(dbContext));
                _connectionStringName = dbContext.InternalContext.ConnectionStringName;
                _connectionProviderName = dbContext.InternalContext.ProviderName;
                _connectionStringOrigin = dbContext.InternalContext.ConnectionStringOrigin;
            }
        }
    }
    public virtual bool IsConstructible => _isConstructible;
}

CreateActivator基本上搜索 DbContext 类型或您的 DbContext 类型的无参数构造函数IDbContextFactory<MyContext>执行并返回一个Func<MyContext>. Then CreateInstance调用该激活器。不幸的是,DbConnectionInfo connectionInfo的参数DbContextInfo激活器不使用构造函数,但仅在创建上下文实例后才应用(为简洁起见,删除了不相关的代码):

public virtual DbContext CreateInstance()
{
    dbContext = _activator == null ? null : _activator();
    dbContext.InternalContext.ApplyContextInfo(this);
    return dbContext;
}

然后,里面ApplyContextInfo,神奇的事情发生了:连接信息(来自_connectionInfo) 在新创建的上下文中被覆盖。

所以,鉴于你must有一个无参数构造函数,我的解决方案与您的类似,但有一些更积极的检查。

  1. 默认构造函数仅在编译时添加Debug配置。
  2. 如果没有从以下位置调用,默认构造函数将抛出异常Add-Migration命令。

这是我的上下文:

public class MyContext : DbContext
{
    static MyContext()
    {
        System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, MyContextConfiguration>(useSuppliedContext: true));
    }

#if DEBUG
    public MyContext()
    {
        var stackTrace = new System.Diagnostics.StackTrace();
        var isMigration = stackTrace.GetFrames()?.Any(e => e.GetMethod().DeclaringType?.Namespace == typeof(System.Data.Entity.Migrations.Design.ToolingFacade).Namespace) ?? false;
        if (!isMigration)
            throw new InvalidOperationException($"The {GetType().Name} default constructor must be used exclusively for running Add-Migration in the Package Manager Console.");
    }
#endif
    // ...
}

那我终于可以跑了

Add-Migration -Verbose -ConnectionString "Server=myServer;Database=myDatabase;Integrated Security=SSPI" -ConnectionProviderName "System.Data.SqlClient"

为了运行迁移,我还没有找到使用的解决方案DbMigrator明确地,所以我使用MigrateDatabaseToLatestVersion数据库初始值设定项useSuppliedContext: true如中所解释的如何将连接字符串注入 IDbContextFactory 的实例中? https://stackoverflow.com/questions/18734496/how-do-i-inject-a-connection-string-into-an-instance-of-idbcontextfactoryt/32478553#32478553 .

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

不带无参数 DbContext 和 DbContextFactory 构造函数的 Add-Migration 的相关文章

随机推荐

  • 在 WinRT 应用程序中处理 2、3、4、5 个手指点击、双击和按住手势

    我可以轻松处理 1 根手指Tapped DoubleTap and Holding像这样的手势 public MainPage this InitializeComponent this Tapped mc Tapped this Doub
  • 如何旋转MKMapView并保持Annotation和视图不旋转?

    我正在制作一个显示用户当前位置的 MKMapView 我想像 Google 地图应用程序一样旋转地图 但不旋转注释 我使用以下代码 void locationManager CLLocationManager manager didUpda
  • 替换 msbuild 变量中的字符

    我需要替换要传递给 msbuild 4 中的 exec 任务的变量中的字符 具体来说 我需要替换所有出现的反斜杠 带有正斜杠 in the MSBuildProjectDirectory 多变的 eg
  • play2框架我的模板是没有看到的。 : 包views.html不存在

    问题是控制器看不到我想使用的模板 etl admin compile info 编译 3 个 Scala 源代码和 4 个 Java 源代码 来源 D ECLIPSE WORKSPACES play2 apps etl admin targ
  • 在谷歌地图图块上绘制形状文件[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一些形状文件想要在 Google 地图图块上绘制 做到这一点最有效的方法是什么 一种方法可能是使用 pkg RgoogleMaps
  • 如何传递手势选择器的参数

    我向标签添加了一个手势 当点击时我想触发 showlbl 它将以 int 作为参数 但是我收到一个编译器错误 UITapGestureRecognizer gestlbl0 UITapGestureRecognizer alloc init
  • Spring 视图不尊重 @UIScope 注释?

    我遇到 Vaadin spring 注释的问题 UIScope 定义如下 SpringComponent SpringView name AdminView VIEW NAME UIScope public class AdminView
  • Symfony 4 全局路由前缀

    我在 Symfony 4 应用程序中找不到有关全局路由前缀的任何信息 唯一的thing https symfony com blog new in symfony 3 4 prefix all controller route names我
  • ImportError:尝试导入祝福时没有名为“_curses”的模块

    我正在尝试运行这个 from blessings import Terminal t Terminal print t bold Hi there print t bold red on bright green It hurts my e
  • 处理不平衡问题后,数据高度倾斜,准确性下降

    在对数据进行预处理 例如缺失值替换和异常值检测 后 我使用随机化方法对数据进行分区 并使用 WEKA 删除百分比过滤器 我的数据集是一个高度倾斜的数据集 不平衡比为 6 1 对应于负类和正类 如果我使用朴素贝叶斯分类器对数据进行分类 而不处
  • TSQL:字符串错误的日期时间

    有一些与此相关的帖子 但我对 TSQL 很陌生 我无法理解它们 所以请原谅 我的程序有 BEGIN TRY INSERT INTO dbo myprocedure Mydate VALUES CONVERT DATETIME mydate
  • C# using 语句捕获错误

    我只是查看 using 语句 我一直知道它的作用 但直到现在还没有尝试使用它 我想出了以下代码 using SqlCommand cmd new SqlCommand reportDataSource new SqlConnection S
  • 调用远程ESB客户端错误

    我正在尝试从远程客户端发送和 esb 消息 但我不断收到此错误 org jboss soa esb listeners message MessageDeliverException org apache ws scout transpor
  • 如何使 Google Chrome 扩展示例正常工作?

    最近我决定编写一个非常简单的 Google Chrome 扩展 它要做的就是当用户按下扩展程序的按钮时 使用 JavaScript 从网页中隐藏一些 DOM 元素 由于我对 Chrome 扩展一无所知 所以我开始阅读教程 然后我发现了这个
  • 了解青春痘

    我不明白这个 DI容器 是如何使用的 官方网站上显示的示例没有告诉我任何信息 http pimple sensiolabs org http pimple sensiolabs org 基本上我有一个简单的站点 它由一组类组成 DB 类 C
  • Emacs:Tramp 不起作用

    我尝试通过 Emacs 通过 Tramp 打开远程文件 require tramp setq tramp default method ssh 我收到一条来自 Emacs 的消息 TRAMP 等待远程 shell 的提示 Emacs 挂起并
  • 如何从AVAudioEngine的installTap高频获取缓冲区

    我希望像 iOS 语音备忘录应用程序一样在屏幕上渲染音频波形 因此我使用 AVAudioEngine 并在输入节点上安装 Tap 但它以 0 1 秒的频率提供最快的回调 我需要以更快的频率获取缓冲区数据 以便可以在屏幕上绘制越来越多的波形
  • T4 FieldName 采用驼峰命名法,不带下划线?

    我正在使用 T4 生成一些类定义 并发现我的字段名称前面有一个下划线 我已经设定 code CamelCaseFields true 只是为了安全起见 尽管我知道这是默认设置 但最终仍然是 myField 而不是 myField 如何生成不
  • 将日志文件转换为 json?

    我有以下格式的日志文件 我需要使用 python 将日志文件转换为 json 文件 怎样才能制作出来呢 2015 07 13 00 03 05 976 hostname 1499918592344 UZA Anonymous Anonymo
  • 不带无参数 DbContext 和 DbContextFactory 构造函数的 Add-Migration

    我的应用程序没有无参数构造函数DbContext实现 我不喜欢提供无参数构造函数IDbContextFactory lt gt 执行 原因是我想控制 DbContext 指向的位置 这就是为什么我的所有构造函数都会请求 Connection