Первое расположение базы данных EF6 для файлов cscdl, .msl и.ssdl

У меня есть приложение WPF, содержащее проект EF6.0 с первым подходом к базе данных. Пользователь должен иметь возможность открывать разные базы данных в разных местах с разными именами. Так что моя ConnectionString не приходит из App.config, как здесь:

  <connectionStrings>
<add name="SQLiteDatabaseEntities" connectionString="metadata=res://*/SQLiteModel.csdl|res://*/SQLiteModel.ssdl|res://*/SQLiteModel.msl;provider=System.Data.SQLite.EF6;provider connection string=&quot;data source=C:\SomePathThatMayChange\Database.sqlite;useutf16encoding=True;synchronous=Full&quot;" providerName="System.Data.EntityClient" />

Я скорее должен создать его для себя в коде и установить источник данных в правильном месте:

if (false == File.Exists(fullPathAndFilename))
{
    return string.Empty;
}
EntityConnectionStringBuilder entityConnectionStringBuilder = new EntityConnectionStringBuilder();
entityConnectionStringBuilder.Name = "SQLiteConnection";
entityConnectionStringBuilder.Provider = "System.Data.EntityClient";
entityConnectionStringBuilder.ConnectionString = "metadata=res://*/SQLiteModel.csdl|res://*/SQLiteModel.ssdl|res://*/SQLiteModel.msl;provider=System.Data.SQLite.EF6;provider connection string=';data source=" + fullPathAndFilename + "';";
return entityConnectionStringBuilder.ToString();

Теперь я изменил структуру своего приложения, добавив другие проекты и поместив элементы EF в отдельный проект (отличный от основного проекта), который содержит только элементы базы данных. При отладке следующего кода я сталкиваюсь с исключением

    try
{
    using (Entities context = new Entities(ConnectionString))
    {
        context.Database.Connection.Open();
        using (System.Data.Entity.DbContextTransaction dbTran = context.Database.BeginTransaction())
        {
            try
            {
                // Do things:
                // ...
                return true;
            }
            catch
            {
                dbTran.Rollback();
            }
        }
    }
}
catch (Exception ex)
{
    System.Diagnostics.Trace.WriteLine(ex.Message);
}

Сообщение об исключении: Указанная схема недопустима. Ошибки: SQLiteModel.ssdl(2,2): ошибка 0152: не найден поставщик Entity Framework для поставщика ADO.NET с именем-инвариантом System.Data.SQLite.EF6. Убедитесь, что поставщик зарегистрирован в разделе "entityFramework" конфигурационного файла приложения.

Я обнаружил, что некоторые файлы находятся не там, где они должны быть. Это SQLiteModel.csdl, SQLiteModel.msl и SQLiteModel.ssdl. Они находятся в каталоге...\obj\Debug\edmxResourcesToEmbed\. Я также обнаружил, что в файле *.ssdl также есть источник данных, указанный в поле ProviderManifestToken="источник данных =

<Schema Namespace="RohlingModel.Store" Provider="System.Data.SQLite.EF6" ProviderManifestToken="data source=C:\SomePathThatMayChange\Database.sqlite" Alias="Self" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm/ssdl">

Я предполагаю, что моя программа сработала только случайно в первый раз. И теперь у меня есть несколько вопросов: 1. Действительно ли мне нужно встраивать этот *ssdl-файл, содержащий фиксированное местоположение для источника данных? 2. Можно ли вообще изменить местоположение базы данных позже, указав источник данных в ConnectionString? 3. В этой ситуации вообще возможен подход с использованием базы данных? 4. Где я должен копировать / встраивать эти файлы в мое мультипроектное решение?

Заранее спасибо!

Обновление: я узнал, что мои вопросы глупы. Кажется, проблема в том, что в моем основном проекте app.config не содержит всей необходимой информации. Поскольку я хочу отделить базу данных от остальных, в app.config основного проекта вообще не должно быть вещей, связанных с EF.

Я решил проблему, запрограммировав 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" />
  </configSections>
  <entityFramework>
    <defaultConnectionFactory type = "System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework" >
      < parameters >
        < parameter value="mssqllocaldb" />
      </parameters>
    </defaultConnectionFactory>
    <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>
  </entityFramework>
  <system.data>
    <DbProviderFactories>
      <remove invariant = "System.Data.SQLite.EF6" />
      < remove invariant="System.Data.SQLite" />
      <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" />
      <add name = "SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite, Version=1.0.104.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" />
    </DbProviderFactories>
  </system.data>
  <connectionStrings>
    <add name = "SQLiteDatabaseEntities" connectionString="metadata=res://*/SQLiteModel.csdl|res://*/SQLiteModel.ssdl|res://*/SQLiteModel.msl;provider=System.Data.SQLite.EF6;provider connection string=&quot;data source=C:\SomePath\SQLiteDatabase.Template;useutf16encoding=True;synchronous=Full&quot;" providerName="System.Data.EntityClient" />
    <add name = "Entities" connectionString="metadata=res://*/SQLiteModel.csdl|res://*/SQLiteModel.ssdl|res://*/SQLiteModel.msl;provider=System.Data.SQLite.EF6;provider connection string=&quot;data source=C:\SomePath\SQLiteDatabase.Template;useutf16encoding=True;synchronous=Full&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
</configuration>

Я создал класс MySQLiteConfiguration, который выглядит так:

        public class MySQLiteConfiguration : DbConfiguration
    {
        public MySQLiteConfiguration()
        {
            SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.LocalDbConnectionFactory("mssqllocaldb"));
            SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);

            // this provider is part of the App.config. However, it seems to be needed only for updating the model from the database in this "database first approach" rather than reading from or writing to the database.
            //SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);

            DbProviderServices sqLiteProviderServices = (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices));
            SetProviderServices("System.Data.SQLite", sqLiteProviderServices);
            SetProviderServices("System.Data.SQLite.EF6", sqLiteProviderServices);

            // These providers have to be specified in detail. Since they are there already they must be exchanged:
            List<Provider> providersToExchange = new List<Provider>();
            providersToExchange.Add(new Provider("SQLite Data Provider (Entity Framework 6)", "System.Data.SQLite.EF6", ".NET Framework Data Provider for SQLite (Entity Framework 6)", "System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6"));
            providersToExchange.Add(new Provider("SQLite Data Provider", "System.Data.SQLite", ".NET Framework Data Provider for SQLite", "System.Data.SQLite.SQLiteFactory, System.Data.SQLite, Version=1.0.104.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139"));

            try
            {
                System.Data.DataRowCollection rows = (System.Configuration.ConfigurationManager.GetSection("system.data") as System.Data.DataSet).Tables?[0]?.Rows;

                if (rows != null)
                {
                    foreach (Provider provider in providersToExchange)
                    {
                        for (int i = 0; i < rows.Count; i++)
                        {
                            if (rows[i]["InvariantName"] as string == provider.InvariantName)
                            {
                                rows.RemoveAt(i);
                                break;
                            }
                        }
                    }

                    foreach (Provider provider in providersToExchange)
                    {
                        rows.Add(provider.InvariantName, provider.Description, provider.Name, provider.Type);
                    }
                }
            }
            catch (System.Data.ConstraintException constraintException)
            {
                System.Diagnostics.Debug.Assert(false, constraintException.Message);
            }
        }

        private class Provider
        {
            internal string Name { get; set; }
            internal string InvariantName { get; set; }
            internal string Description { get; set; }
            internal string Type { get; set; }

            internal Provider(string name, string invariantName, string description, string type)
            {
                Name = name;
                InvariantName = invariantName;
                Description = description;
                Type = type;
            }
        }
    }

и этот класс используется для настройки контекста:

     [DbConfigurationType(typeof(MySQLiteConfiguration))]
    public partial class Entities : DbContext
    {
        public Entities(string connectionString)
            : base(connectionString)
        { }
    }

При работе с контекстом я использую конструктор, который передает мою собственную строку подключения:

            try
        {
            using (Entities context = new Entities(ConnectionString))
            {
                // Do things...
                // ...
            }
        }
        catch { }

Я прошу прощения за мои глупые вопросы. Я надеюсь помочь некоторым людям, которые испытывают трудные времена, когда делают свои первые шаги с Entity Framework 6.0 и SQLite.

С уважением

0 ответов

Другие вопросы по тегам