【发布时间】:2019-11-29 22:12:18
【问题描述】:
我正在编写一个小应用程序,作为练习来学习如何在 C# .NET 中使用 SQL 数据库。我的应用程序尝试打开与数据库的连接,如果失败,它会假定数据库不存在并创建它。该数据库仅由我的应用程序使用,并且始终是本地的,因此它比许多其他数据库情况要简单得多。下面是代码,基于我在 SO 以及 Andrew Troelsen 的“Pro C# 7: With .NET and .NET Core”中阅读的内容:
private static DbConnection connection = null;
private static MyAppModels context = null;
public static void SetupDatabase()
{
string dataProvider = "System.Data.SqlClient";
DbProviderFactory factory = DbProviderFactories.GetFactory(dataProvider);
// get connection object (closes automatically at end of using scope)
connection = factory.CreateConnection();
if (connection == null) { /* throw Exception */ }
string connectionString = @"Data Source=(localdb)\mssqllocaldb;Initial Catalog=MyAppDB;Integrated Security=True";
connection.ConnectionString = connectionString;
try { connection.Open(); }
catch (Exception)
{
// database could not be found; try to create it...
connection.ConnectionString = @"Data Source=(localdb)\mssqllocaldb;Integrated Security=True;database=master";
connection.Open();
string str = "CREATE DATABASE MyAppDB ON PRIMARY " +
"(NAME = MyApp_Data, FILENAME = 'C:\\Users\\Me\\Documents\\MyApp\\MyAppData.mdf', " +
"SIZE = 2MB, MAXSIZE = 50MB, FILEGROWTH = 10%) " +
"LOG ON (NAME = MyApp_Log, FILENAME = 'C:\\Users\\Me\\Documents\\MyApp\\MyAppLog.ldf', " +
"SIZE = 1MB, MAXSIZE = 10MB, FILEGROWTH = 10%)";
DbCommand myCommand = connection.CreateCommand();
myCommand.CommandText = str;
try { myCommand.ExecuteNonQuery(); }
catch (System.Exception ex) { /* throw Exception */ }
}
context = new MyAppModels(connection);
return;
}
在我尝试向表中添加数据之前,这段代码似乎可以毫无问题地执行,此时我收到以下错误:
“支持 'MyAppModels' 上下文的模型在创建数据库后发生了变化。考虑使用 Code First 迁移来更新数据库 (http://go.microsoft.com/fwlink/?LinkId=238269)。”
如果我退出我的应用程序并重新打开它,它就能够连接到现有的数据库并毫无问题地添加记录。但我不希望我的应用程序的用户在首次安装后被要求退出并重新打开应用程序,只是为了解决这个问题!
我在这里查看了其他几个帖子,包括:
The model backing the 'POSContext' context has changed since the database was created
The model backing the context has changed since the database was created
这两个似乎都指向同一个解决方案。此外,第二个引用了 Microsoft EF 团队成员的以下引用:
第一次创建模型时,我们会运行 DatabaseInitializer 来执行诸如创建数据库(如果数据库不存在)或添加种子数据等操作。默认的 DatabaseInitializer 尝试将使用模型所需的数据库架构与存储在使用数据库创建的 EdmMetadata 表中的架构哈希进行比较(当 Code First 是创建数据库的人时)。现有的数据库不会有 EdmMetadata 表,因此不会有哈希......如果该表丢失,今天的实现将抛出。在我们发布最终版本之前,我们将努力改变这种行为,因为它是默认的。在此之前,现有数据库通常不需要任何数据库初始化程序,因此可以通过调用以下方法为您的上下文类型关闭它:
Database.SetInitializer<YourDbContext>(null);
我真的不明白这一切。但我还是尝试将该代码添加到我的 DbContext 类中:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<MyAppModels>(null);
base.OnModelCreating(modelBuilder);
}
现在,当我尝试将第一条记录添加到表时出现以下错误:
“更新条目时发生错误。有关详细信息,请参阅内部异常。”
内部异常: “字符串或二进制数据将被截断。语句已终止。”
现在,如果我关闭并重新打开应用程序,每次都会出现相同的错误。所以现在情况更糟了。通过查看其他 SO 帖子,我看到此错误指向输入数据库的数据超出字段大小的问题。但是我在尝试添加的第一条记录上遇到了错误,它肯定不会超过该表中的任何字段大小。
我怀疑我不应该将 null 传递给 SetInitializer()。我注意到了评论,“......我们运行一个 DatabaseInitializer 来执行诸如创建数据库(如果它不存在)或添加种子数据之类的事情。”我的代码已经在尝试处理数据库创建。我的应用程序不应该这样做吗? SetInitializer() 如何知道放置数据库或 MAXSIZE 的位置?而且我认为我也不需要它来“添加种子数据”。
我还注意到了这条评论,“我们将在发布最终(原文如此)版本之前努力改变这种行为,因为它是默认的。”这使它听起来像一个错误。该评论是大约 9 年前写的,所以我希望它已经修复了。
在此期间,有没有人有任何关于如何让它正常工作的提示?
--更新--
我能够通过对上面显示的创建代码的一小部分添加来完成这项工作:
myCommand.ExecuteNonQuery();
// close & try again to open the database
connection.Close();
connection.ConnectionString = @"Data Source=(localdb)\mssqllocaldb;Integrated Security=True;Initial Catalog=MyAppDB";
connection.Open();
似乎没有必要,但它确实有效......
然后我尝试了其他方法。正如我在几个示例教程中看到的那样,我用一行替换了 SetupDatabase() 中的所有代码:
context = new MyAppModels();
这允许/依赖 EF 打开数据库,并在必要时创建它(在某些未定义/默认位置)。这在数据库已经存在时有效,但是当需要创建数据库时,它失败了:
System.Data.SqlClient.SqlException HResult=0x80131904
Message=CREATE FILE 遇到操作系统错误 5(访问被拒绝。) 尝试打开或创建物理文件时 'C:\Users\MyAppDB.mdf'。创建数据库失败。一些文件 无法创建列出的名称。检查相关错误。来源=.Net SqlClient 数据提供者
注意和 MyAppDB.mdf 之间没有反斜杠。我不知道为什么会发生这种情况或如何解决它。我在 App.config 中看不到任何可以控制它的明显内容...
<connectionStrings>
<add name="MyAppConnection" connectionString="data source=(localdb)\mssqllocaldb;initial catalog=MyAppDB;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
</connectionStrings>
有人可以帮我解决这个问题,这样我就可以使用“纯”EF,还是我需要回到我的 hack 工作......?
【问题讨论】:
标签: c# .net sql-server database entity-framework