【问题标题】:How to Pass Full Sqlite Connection String to DbContext如何将完整的 Sqlite 连接字符串传递给 DbContext
【发布时间】:2017-09-13 20:41:54
【问题描述】:

我正在尝试将完整的连接字符串作为参数传递给 DbContext 构造函数,但出现此错误:

无法完成操作。提供的 SqlConnection 未指定初始目录或 AttachDBFileName。

这是我尝试过的:

public DatabaseContext() :base(@"Data Source=|DataDirectory|ComponentDatabase.sqlite") {}

问题只能是连接字符串,因为我能够使用来自App.config 的连接字符串连接我的数据库,如下所示:

App.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>
  <entityFramework>
    <providers>
      <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
    </providers>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="mssqllocaldb" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>
  <connectionStrings>
    <!-- use AppDomain.SetData to set the DataDirectory -->
    <add name="MapDbConnectionStr" connectionString="Data Source=|DataDirectory|ComponentDatabase.sqlite" providerName="System.Data.SQLite" />
  </connectionStrings>
  <system.data>
    <DbProviderFactories>
      <remove invariant="System.Data.SQLite.EF6" />
      <add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" />
    <remove invariant="System.Data.SQLite" /><add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /></DbProviderFactories>
  </system.data>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Data.SQLite" publicKeyToken="db937bc2d44ff139" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.0.105.2" newVersion="1.0.105.2" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Data.SQLite.EF6" publicKeyToken="db937bc2d44ff139" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.0.105.2" newVersion="1.0.105.2" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

DbContext

public DatabaseContext() :base("MapDbConnectionStr") {}

附:我知道App.config 有很多不必要的行,是的。

【问题讨论】:

  • 不确定是否重复,但这可能会有所帮助stackoverflow.com/a/35982626/2946329
  • 不,这是关于在 MSSQL 数据库的配置文件中缺少初始目录,这是关于将实际连接字符串传递给 Sqlite 中的构造函数。 AFAIK Sqlite 没有初始目录选项。就算有,直接传给构造函数还是找不到正确的字符串形式。
  • 如果您使用 SQLite 数据库,这是一个不需要任何配置文件的解决方案 - EF6, SQLite won't work without App.confg
  • @IvanStoev 看来它可以解决我的问题,尽快尝试,谢谢。

标签: c# entity-framework sqlite


【解决方案1】:

据我所知,您尝试连接的数据库类型没有连接工厂。

您可以编写自己的连接工厂:

public class MySqlLiteConnectionFactory : IDbConnectionFactory
{
    public DbConnection CreateConnection(string connectionString)
    {
        return new SQLiteConnection(connectionString);
    }
}

现在在 app.config 中找到 defaulConnectionfactory 的条目并替换指定类型的行。目前那会是这样的:

<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">

把它改成这样:

<defaultConnectionFactory type="MyNamespace.MySQLiteConnectionFactory, MyAssemblyHere" />

您现在应该能够正确使用 Context ctor(字符串 connectionString)。

还有一种方法是在不依赖 appsettings 的情况下执行此操作,EF 6 及更高版本支持基于代码的配置。

所以你可以用看起来有点像这样的配置来做一些事情:

DbConfiguration.Loaded += (_, a) => 
   { 
       a.ReplaceService<DbProviderServices>((s, k) => new MyProviderServices(s)); 
       a.ReplaceService<IDbConnectionFactory>((s, k) => new MyConnectionFactory(s)); 
   };

完整的细节记录在here at microsoft:

【讨论】:

  • 感谢您的回答。有没有办法完全避免依赖app.config?我正在尝试传递完整的连接字符串,因为我想避免使用 app.config。
  • 我想我找到了,在DbContext 类中创建了一个类SQLiteConfiguration: DbConfiguration,但我仍然得到相同的Unable to complete operation. The supplied SqlConnection does not specify an initial catalog or AttachDBFileName.
  • 我对这篇文章进行了扩充,应该可以帮助您实现目标。
  • 终于解决了。方法如下:除了stackoverflow.com/questions/43615926/…,我还使用了您的答案。并从 app.config 中删除了连接字符串和实体框架部分(这部分是必需的,否则错误仍然存​​在)。
  • 我已将其他帖子添加为最喜欢的 Saibot,这很有用
【解决方案2】:

使用配置文件中的名称是可行的,因为它可以根据提供的随附配置确定提供程序类型。当直接在构造函数中使用连接字符串时,它无法确定连接字符串是用于 SQLite 并假定为 MSSQL,因此它正在尝试使用SqlConnection。因此,您遇到了错误消息。

注意:

与数据库的连接(包括数据库名称) 可以通过多种方式指定。如果无参数 DbContext 构造函数是从派生的上下文中调用的,然后是 派生上下文用于在 app.config 中查找连接字符串 或 web.config 文件。如果未找到连接字符串,则名称为 传递给在数据库上注册的 DefaultConnectionFactory 班级。然后连接工厂使用上下文名称作为 默认连接字符串中的数据库名称。 (此默认连接 字符串指向本地计算机上的 .\SQLEXPRESS,除非有不同的 DefaultConnectionFactory 已注册。)而不是使用派生的 上下文名称,也可以指定连接/数据库名称 通过将名称显式传递给 DbContext 构造函数之一 这需要一个字符串。名称也可以通过形式传递 “name=myname”,在这种情况下,必须在配置文件中找到名称 否则会抛出异常。请注意,在 app.config 或 web.config 文件可以是正常的数据库连接 字符串(不是特殊的实体框架连接字符串),其中 如果 DbContext 将使用 Code First。但是,如果连接 在配置文件中发现是一个特殊的实体框架连接 字符串,然后 DbContext 将首先使用 Database/Model 和模型 将使用连接字符串中指定的。现有的或 也可以使用显式创建的 DbConnection 代替 数据库/连接名称。

Taken from the class remarks for DbContext

最后引用的那句话很突出……

也可以使用现有的或显式创建的 DbConnection 而不是数据库/连接名称。

你可以考虑使用SQLiteConnection

public class DatabaseContext : DbContext {

    public DatabaseContext() 
        :base(new SQLiteConnection(@"Data Source=|DataDirectory|ComponentDatabase.sqlite"), true) {
        //...
    }

    //...
}

【讨论】:

  • 好吧,我问的是传递完整的连接字符串,而不是传递连接对象。当您传递连接对象时,实体框架无法完全控制它,因此将来可能会导致小规模问题。我宁愿避免它。
  • 是的,但没有帮助。
【解决方案3】:

正如我正确理解的那样,它可能会有所帮助,请使用带有 db 上下文选项的构建器。我用的是SqlServer,不过应该不会有太多变化。

var builder = new DbContextOptionsBuilder<MapDbContext>();
builder.UseSqlServer(ConfigurationManager.ConnectionStrings["MapDbConnectionStr"].ConnectionString), opt => opt.EnableRetryOnFailure());
var mycontext = new MapDbContext(builder.Options);

public MapDbContext(DbContextOptions<MapDbContext> options)
        : base(options)
    { }

希望对你有帮助,祝你好运。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-18
    • 2011-06-15
    • 2020-12-07
    • 1970-01-01
    • 1970-01-01
    • 2020-06-02
    相关资源
    最近更新 更多