EF6数据库cscdl,.msl和.ssdl文件的第一个位置

时间:2017-04-04 16:28:13

标签: c# wpf entity-framework sqlite 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:找不到具有不变名称&#39; System.Data.SQLite.EF6&#39;的ADO.NET提供程序的实体框架提供程序。 确保提供商已在&#39; entityFramework&#39;中注册。应用程序配置文件的一部分。

我发现有些文件不在应有的位置。这就是SQLiteModel.csdl,SQLiteModel.msl和SQLiteModel.ssdl。 它们位于... \ obj \ Debug \ edmxResourcesToEmbed \目录中。 我还发现在* .ssdl文件中还有一个在ProviderManifestToken =&#34; data source =

下指定的数据源
<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 个答案:

没有答案