【问题标题】:How to programatically set database filename?如何以编程方式设置数据库文件名?
【发布时间】:2014-06-14 19:17:41
【问题描述】:

this tutorial 之后,我创建了我的DbConfiguration 类:

class ImgSigDbConfig : DbConfiguration
{
    public ImgSigDbConfig()
    {
        SetDefaultConnectionFactory(new LocalDbConnectionFactory("v11.0")); 
    }
}

并告诉我的DbContext 使用它:

[DbConfigurationType(typeof(ImgSigDbConfig))] 
class ImgSimContext : DbContext 
{

这似乎连接良好,但我不知道它在哪里存储我的数据,我不喜欢这样。我希望它将所有内容保存到 App_Data 文件夹中的文件中。如何从我的 ImgSigDbConfig 构造函数中指定它? (假设我对 SQL 服务器连接一无所知)


做了更多的挖掘并想出了这个:

public ImgSigDbConfig()
{
    var sqlConnBuilder = new SqlConnectionStringBuilder();
    sqlConnBuilder.DataSource = ".";
    sqlConnBuilder.InitialCatalog = "ImgSim.ImgSimContext";
    sqlConnBuilder.IntegratedSecurity = true;
    sqlConnBuilder.AttachDBFilename = @"App_Data\database.mdf";

    SetDefaultConnectionFactory(new LocalDbConnectionFactory("v11.0", sqlConnBuilder.ToString()));
}

但现在它抛出:

提供者未返回 ProviderManifestToken 字符串


根据 haim 和 gunther 的建议,我删除了多余的连接设置:

class ImgSigDbConfig : DbConfiguration
{
    public ImgSigDbConfig()
    {
        var sqlConnBuilder = new SqlConnectionStringBuilder();

        sqlConnBuilder.IntegratedSecurity = true;
        sqlConnBuilder.MultipleActiveResultSets = true;

        SetDefaultConnectionFactory(new LocalDbConnectionFactory("v11.0", sqlConnBuilder.ToString()));
        SetManifestTokenResolver(new DefaultManifestTokenResolver());
    }
}

并将它们移到 Program.cs 中:

var conn = new SqlConnectionStringBuilder
{
    AttachDBFilename = @"App_Data\database.mdf",
    //InitialCatalog = "ImgSim.ImgSimContext",
};

using (var db = new ImgSimContext(conn.ToString()))

但即便如此,我还是得到了带有 InnerException 的 System.Data.Entity.Core.ProviderIncompatibleException

提供者未返回 ProviderManifestToken 字符串。

即使我设置了SetManifestTokenResolver -- 我猜默认设置不起作用??

【问题讨论】:

  • 我不是 EF 专家,所以我可能会听到您所理解的内容 - 但通常您在 web.config 或 app.config 中提供一个名称与您的名称匹配的连接字符串上下文(ImgSimContext)。这将是使用的数据库,因此您可以确切地知道数据的去向。如果这就是你的意思,我会充实一个答案。
  • @Ian 如果我可以直接在 C# 中编写 XML,我宁愿不编写它。我对此一无所知——我已经习惯了 MySQL + linux。在那个环境中,我启动 mysql 守护程序,以编程方式设置一些连接设置,然后连接到它。我可以看到守护进程在我的进程中运行,并且可以在磁盘上找到数据。我可以使用 SqlYog 或 PMA 查看我的数据。我不知道 Visual Studio 为我做了什么。每次我运行我的应用程序时都会启动 SQL Express 服务器吗? “localdb”是sqlite的等价物吗?磁盘上的数据在哪里?如何查看?
  • localDB 是某种轻量级 SQL(不确定到底是什么)。你有 Sql Server Management Studio 吗?如果是这样,请启动与(localdb)\v11.0 的连接,我认为您会看到列出的数据库
  • 为什么用无效的连接字符串初始化上下文?
  • @haim770:嗯..?因为我不知道自己在做什么?

标签: c# entity-framework-6.1


【解决方案1】:

LocalDbConnectionFactory 构造函数 v11.0 允许连接到 sqlserver 2012,默认情况下它会尝试在 app.config 中查找连接字符串的名称作为上下文全名。假设您没有在 config 中指定连接字符串,并且想要创建一个名为 Test 的数据库(在下面指定的数据目录中),那么您需要像这样设置构造函数:

   [DbConfigurationType(typeof(ImgSigDbConfig))]
class MyDbContext : DbContext
{
    public MyDbContext(string nameOrConnectionString)
        : base(nameOrConnectionString)
    {
    }

    public DbSet<Person> Persons { get; set; }
}

现在你可以调用上下文了:

AppDomain.CurrentDomain.SetData("DataDirectory", @"c:\App\DataDirectory");
        MyDbContext myDbContext = new MyDbContext("test"); //this is the name
        myDbContext.Persons.Add(new Person() { Id = 1, Name = "Name1" });
        myDbContext.SaveChanges();

配置将保持不变:

class ImgSigDbConfig : DbConfiguration
{
    public ImgSigDbConfig()
    {
        SetDefaultConnectionFactory(new LocalDbConnectionFactory("v11.0"));
    }
}

注意我正在手动设置数据目录,因为它不是网络应用程序。您需要授予此目录的权限,以便可以创建和附加新数据库。 我的 app.config 是这样的:

    <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>  <connectionStrings>
  </connectionStrings>
  <entityFramework>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>

【讨论】:

  • 嗯,做到了。我不太清楚为什么这么复杂。
  • 如何给文件夹权限?除了我的项目文件夹/App_Data 之外的任何其他内容都失败了吗?
  • 您应该能够选择文件夹,右键单击属性,然后将用户设置为具有运行应用程序的写入权限。
  • 你的sql server在哪个用户下运行?它也有这个文件夹的权限吗?
【解决方案2】:

所以默认情况下,Entity Framework 将寻找一个连接字符串来确定它应该打开哪个数据库,它当前使用的是 SQL Express 的一个版本(请参阅here)。这只是让您轻松开发的默认设置。

一个典型的网站会有一个您可以找到的web.config 文件。在那里你会看到类似的东西:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
          <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=testdb;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\testdb.mdf" providerName="System.Data.SqlClient" />
  </connectionStrings>

对于 Windows 窗体/控制台应用程序,将有一个 app.config,但它们的用途相同。

此连接字符串需要修改以使用您感兴趣的数据库,此时我推荐connectionstrings.com。你可以让它指向 SQL、Oracle 或任何你喜欢的东西。

【讨论】:

    【解决方案3】:

    您可以根据提供给 ImgSigContext 的连接字符串创建数据库

    示例:

    public class ImgSigContext : DbContext{
       public ImgSigContext(string connectionString) : base(connectionString)
    }
    

    并通过使用创建它

    string connString = "..."; //here comes a valid connectionstring
    bool created = new ImgSigContext(connString).Database.CreateIfNotExists();
    //returns true if database didn't exist and is succesfully created
    //works from Entity FrameWork 5 and up
    

    或者像这样

    // will automatically create if migrations is enabled
    using(var context = new ImgSigContext(connString))
    {
       // some logic comes here
    }
    

    【讨论】:

      【解决方案4】:

      MyLocalDbConnectionFactory 构造函数上的baseConnectionString 参数的文档明确指出:

      用于数据库选项的连接字符串,而不是 “初始目录”、“数据源”和“AttachDbFilename”。这 'Initial Catalog' 和 'AttachDbFilename' 将被添加到这个 调用 CreateConnection 时基于数据库名称的字符串。这 'Data Source' 将根据 LocalDbVersion 参数设置。

      试试这个:

      var sqlConnBuilder = new SqlConnectionStringBuilder();
      sqlConnBuilder.IntegratedSecurity = true;
      sqlConnBuilder.MultipleActiveResultSets = true;
      

      如果您正在运行控制台应用程序,请确保您的 DataDirectory 已实际设置。使用:AppDomain.CurrentDomain.GetData("DataDirectory")

      【讨论】:

      • 啊哈。没注意到。它确实是一个控制台应用程序。 AppDomain.CurrentDomain.GetData("DataDirectory") 返回空值。 AppDomain.CurrentDomain 说“没有上下文策略”。
      • 尝试将其设置为您的App_Data 或重写原始LocalDbConnectionFactory 以满足您的需求(来源:entityframework.codeplex.com/SourceControl/latest#src/…)。
      • 另外,如果您观看myDbContext.Database.Connection.ConnectionString(使用您当前的代码),您会发现它无效。
      猜你喜欢
      • 1970-01-01
      • 2011-12-11
      • 2017-01-11
      • 2014-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-10
      相关资源
      最近更新 更多