繁体   English   中英

如何使用 EF 创建数据库并开始使用它?

[英]How do I create a database with EF and begin using it?

我有一个正在编写的小应用程序,作为练习来学习如何在 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 Migrations 更新数据库 ( http://go.microsoft.com/fwlink/?LinkId=238269 )。”

如果我退出我的应用程序并重新打开它,它能够连接到现在存在的数据库并毫无问题地添加记录。 但我不希望我的应用程序的用户在首次安装后被要求退出并重新打开应用程序,只是为了解决这个问题!

我在这里查看了其他几个帖子,包括:

自数据库创建以来,支持“POSContext”上下文的模型已更改

自数据库创建以来支持上下文的模型已更改

这些似乎都指向相同的解决方案。 此外,第二个引用了 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 在尝试打开或创建物理文件“C:\Users\MyAppDB.mdf”时遇到操作系统错误 5(访问被拒绝。)。 创建数据库失败。 无法创建列出的某些文件名。 检查相关错误。 Source=.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 ......?

出色地

是代码,基于我在 SO 和“Pro C# 7: With .NET and .NET Core”中阅读的内容

您似乎已经尝试混合使用手动数据库创建和代码优先迁移

而且结局很糟糕。

我们能解决这个问题吗?

是的......有一些额外的细节/代码,它甚至可能需要从头开始重新做很多事情,所以我不确定是否值得花时间,因为你似乎在研究技术,而不是试图解决一些问题某些关键业务内部程序套件中的技术混杂。

因此,我建议您决定要学习什么,并使用标准教程逐步学习:

  1. 您想了解如何使用 EF 上下文和 Code-First 迁移吗? - https://learn.microsoft.com/en-us/ef/ef6/modeling/code-first/migrations/
  2. 想了解如何使用现有数据库进行操作吗? - https://learn.microsoft.com/en-us/ef/ef6/modeling/code-first/workflows/existing-database
  3. 想要了解如何使用基本的 ADO.NET 类(DbConnection、DbDataReader)- https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ado-net-code-examples
  4. 想在两者之间做些什么? - 只需确保在混合之前分别使用过每样东西,并且你真的想尝试一下(学术兴趣/实验欲望很好,但将非标准方法应用于实际问题通常不是一个好主意)。

PS:您似乎正在使用 EF6(就像您使用DatabaseInitializer一样),但实际上我建议您开始学习EF Core ,因为它是 Entity Framework 的最新迭代。

您发布的代码是您将如何使用“动态”SQL“手动”创建数据库。 使用 Entity Framework 时,您根本不需要使用该方法。

开始使用 Entity Framework 的最简单方法之一是使用 Model-First:

  • 向您的项目添加一个新的“ADO.NET 实体数据模型”。
  • 选择“空 EF 设计器模型”。
  • 编辑模型以设计您的数据库。
  • 保存后(或在 VS2019 中,您必须在 .tt 文件上“运行自定义工具”),您将创建所有实体类。
  • 在模型中选择“从模型生成数据库”以生成一个 SQL 文件,其中包含使用该模型创建新数据库所需的所有 SQL 语句。 此步骤还会在数据库和 C# 代码之间创建所有必要的绑定。 (所有这些都存在于幕后。)

添加到模型中的实体成为数据库中的表和 C# 代码中的类。

您添加的属性成为数据库中的字段和 C# 代码中的属性。

您添加的关联在 C# 代码中成为数据库和集合(“导航属性”)中的外键关系。

然后,您可以开始使用 LINQ 和IQueryable在 C# 代码中构建查询。

您可以对模型进行更改,并再次通过“从模型生成数据库”过程来获取创建数据库的新 SQL 文件,但请注意,当您执行脚本时,它将首先核对任何现有数据库。 这在测试时可能没问题,但它也有助于使用版本控制系统,以便您可以看到对 SQL 的更改,然后手动更改数据库结构以确保数据库与模型匹配,而不必删除它第一的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM