Я пытаюсь передать полную строку подключения конструктору 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 содержит много ненужных строк, да.

5
ferit 8 Сен 2017 в 19:14

3 ответа

Лучший ответ

Насколько я знаю, нет фабрики соединений для типа базы данных, к которой вы пытаетесь подключиться.

Вы можете написать свою собственную фабрику соединений:

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

Теперь перейдите и найдите запись для defaulConnectionfactory в app.config и замените строку, которая указывает тип. На данный момент это будет читать что-то вроде этого:

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

Замените его на что-то вроде этого:

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

Теперь вы должны быть в состоянии правильно использовать контекст ctor (строка connectionString).

Есть еще один способ сделать это, не полагаясь на appsettings EF 6, и далее поддерживает конфигурацию на основе кода.

Таким образом, вы можете сделать что-то с конфигурациями, которые выглядят примерно так:

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

Подробные сведения об этом описаны здесь, в Microsoft:

3
krystan honour 13 Сен 2017 в 12:41

Использование имени из файла конфигурации работает, потому что оно может определить тип провайдера, основываясь на прилагаемой конфигурации. При использовании строки подключения непосредственно в конструкторе он не может определить, что строка подключения предназначена для SQLite и предполагает MSSQL, поэтому он пытается использовать SqlConnection. Отсюда и сообщение об ошибке, с которым вы столкнулись.

Принять к сведению:

Подключение к базе данных (включая имя базы данных) может быть указано несколькими способами. Если конструктор DbContext без параметров вызывается из производного контекста, то имя производного контекста используется для поиска строки подключения в файле app.config или web.config. Если строка подключения не найдена, то имя передается в DefaultConnectionFactory, зарегистрированную в классе Database. Затем фабрика соединений использует имя контекста в качестве имени базы данных в строке соединения по умолчанию. (Эта строка подключения по умолчанию указывает на. \ SQLEXPRESS на локальном компьютере, если не зарегистрировано другое DefaultConnectionFactory.) Вместо использования производного имени контекста, имя подключения / базы данных также можно указать явно, передав имя одному из конструкторов DbContext. это занимает строку. Имя также может быть передано в форме «name = myname», и в этом случае имя должно быть найдено в файле конфигурации, иначе будет выдано исключение. Обратите внимание, что соединение, найденное в файле app.config или web.config, может быть обычной строкой соединения с базой данных (не специальной строкой соединения Entity Framework), и в этом случае DbContext будет использовать Code First. Однако, если соединение, найденное в файле конфигурации, является специальной строкой соединения Entity Framework, тогда DbContext будет использовать Database / Model First и будет использоваться модель, указанная в строке соединения. Существующее или явно созданное DbConnection также может использоваться вместо имени базы данных / соединения.

Взятые из класса замечания для DbContext

Последнее цитируемое предложение выделяется ...

Существующее или явно созданное DbConnection также может использоваться вместо имени базы данных / соединения.

Вы могли бы рассмотреть возможность использования SQLiteConnection

public class DatabaseContext : DbContext {

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

    //...
}
2
Nkosi 11 Сен 2017 в 10:22

Как я правильно понял, это может быть полезно, пожалуйста, используйте строитель с опциями контекста БД. Я использую 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)
    { }

Надеюсь, это поможет, удачи.

-1
OleksiiYatsenko 12 Сен 2017 в 11:03