如何将完整的Sqlite连接字符串传递给DbContext

时间:2017-09-08 16:14:27

标签: c# entity-framework sqlite

我试图将完整的连接字符串作为参数传递给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") {}

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

3 个答案:

答案 0 :(得分:3)

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

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

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(string 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

答案 1 :(得分:2)

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

注意:

  

与数据库的连接(包括数据库的名称)   可以用几种方式指定。如果是无参数的DbContext   构造函数是从派生的上下文中调用的,然后是名称   派生上下文用于在app.config中查找连接字符串   或web.config文件。如果没有找到连接字符串,则名称为   传递给在数据库上注册的DefaultConnectionFactory   类。然后,连接工厂使用上下文名称作为   默认连接字符串中的数据库名称。 (此默认连接   字符串指向。\ SQLEXPRESS在本地计算机上除非有所不同   DefaultConnectionFactory已注册。)而不是使用派生的   上下文名称,也可以指定连接/数据库名称   显式通过将名称传递给DbContext构造函数之一   需要一个字符串。名称也可以在表单中传递   “name = myname”,在这种情况下,必须在配置文件中找到该名称   或者会抛出异常。注意在中找到的连接   app.config或web.config文件可以是普通的数据库连接   string(不是特殊的Entity Framework连接字符串)   如果DbContext将使用Code First。但是,如果连接   在配置文件中找到的是一个特殊的Entity Framework连接   字符串,然后DbContext将使用Database / Model First和模型   将使用连接字符串中指定的。现有的或   显式创建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) {
        //...
    }

    //...
}

答案 2 :(得分:-1)

正如我所理解的那样,它可能会有所帮助,请使用带有数据库上下文选项的构建器。我使用的是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)
    { }

希望它有所帮助,祝你好运。