Entity Framework MSSQL Code First 开发
废话不多说,先按步骤做一遍。
五条人啊茂都说了:多动
1、创建应用程序
创建一个控制台应用程序,选择.net framework4.5以上。
2、创建Model类
新建文件夹:Models,然后新建类Course(课程)和Student(学生),代码如下:
//Course.cs: internal class Course { public int Id { get; set; } public string Name { get; set; } //使用虚拟方法的作用是:将启用实体框架的延迟加载功能。 //延迟加载是指在您尝试访问这些属性时,这些属性的内容将自动从数据库加载。 public virtual List<Student> Students { get; set; } } //Student.cs: internal class Student { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public int CourseId { get; set; } //使用虚拟方法的作用是:将启用实体框架的延迟加载功能。 //延迟加载是指在您尝试访问这些属性时,这些属性的内容将自动从数据库加载。 public virtual Course Course { get; set; } }
3、创建数据库上下文
首先添加 EntityFramework NuGet 包。如下图:
然后添加类CourseraContext,代码如下:
internal class CourseraContext : DbContext { public DbSet<Course> Courses { get; set; } public DbSet<Student> Students { get; set; } }
4、在 Program.cs 中实现 Main 方法,代码如下:
static void Main(string[] args) { int option = -1; while (option != 0) { Console.WriteLine("Choose an option (0, 1, 2):" + Environment.NewLine + "1. Enter a course" + Environment.NewLine + "2. Enter a student" + Environment.NewLine + "3. List all courses" + Environment.NewLine + "4. List all students" + Environment.NewLine + "0. Exit" + Environment.NewLine); if (int.TryParse(Console.ReadLine(), out option)) { switch (option) { case 1: EnterCourse(); break; case 2: EnterStudent(); break; case 3: ListAllCourses(); break; case 4: ListAllStudents(); break; } } } Console.WriteLine("Press any key to quit..."); Console.ReadLine(); } private static void ListAllStudents() { throw new NotImplementedException(); } private static void ListAllCourses() { using (var db = new CourseraContext()) { foreach (Course course in db.Courses) Console.WriteLine(string.Format("Course: {0} - {1}", course.Id, course.Name) + Environment.NewLine); } } private static void EnterStudent() { throw new NotImplementedException(); } private static void EnterCourse() { string name = ""; while (name != "0") { Console.WriteLine("Enter name of course (0 to exit):"); name = Console.ReadLine().Trim(); if (name != "0") { using (var db = new CourseraContext()) { Course course = new Course(); course.Name = name; db.Courses.Add(course); db.SaveChanges(); } } } }
5、运行控制台应用程序
运行程序后,按提示输入:1 (回车); English (回车); 0 (回车); 3 (回车)。
运行结果如下图:
是不是很神奇???前面的代码连数据库链接在哪里,数据库名叫什么都没有配置,竟然可以运行成功数据也保存成功了。
带着这些疑问继续往下看
6、程序中并没有配置数据库链接,也没有指定数据库名和表名,为什么程序可以正常运行?数据存储在哪里?
先看下官方的解释:
运行后,DbContext 会自动创建了一个数据库。
- 如果本地 SQL Express 实例可用(默认情况下随 Visual Studio 2010 一起安装),则 Code First 已在该实例上创建了数据库
- (SQL Express的数据库链接字符串:Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\xxx.mdf;Integrated Security=True;User Instance=True)
- 如果 SQL Express 不可用,Code First 将尝试使用LocalDB (默认情况下安装 Visual Studio 2012或之后的版本)
- (LocalDB的数据库链接字符串:Server=(LocalDB)\MSSQLLocalDB; Integrated Security=true ;AttachDbFileName=D:\Data\xxx.mdf)
- 数据库以派生上下文的完全限定名称命名,在本例中为CodeFirstNewDatabaseSample.CourseraContext
(想详细了解这两个数据库的区别,可以看看这个帖:https://www.cnblogs.com/lucky-donkey/p/13544916.html)
看不懂不要紧,你这样理解就好:数据库和表在程序运行时都会自动为你创建。这里由于没有指定数据库链接字符串或数据库名(后面会教如何指定),所以全部采用程序默认的。
默认数据库名:CodeFirstNewDatabaseSample.CourseraContext
由于我用的是 visual studio 2017,所以自带的是LocalDB,默认的服务名称是:(LocalDB)\MSSQLLocalDB。
下面看看如何找到默认创建的数据库。
首先,打开visual studio 2017的【服务器资源管理器】,快捷键:ctrl + alt + s。或者在菜单中打开: “视图” - “服务器资源管理器”,打开后界面如下图:
在【服务器资源管理器】窗口中选中 “数据链接”,鼠标点击右键,选中“添加连接”,然后在弹出的窗口中,“数据源”项点击 【更改】按钮,如下图:
接下来,选中数据源:Microsoft SQL Server,然后点击 确定,如下图:
然后填写服务器名: (LocalDB)\MSSQLLocalDB ,点开数据库名称下拉框,需要等待加载一会,
加载完成后,找到本应用程序自动创建的数据库:CodeFirstNewDatabaseSample.CourseraContext 如下图:
点击确定,再回到【服务器资源管理器】窗口,可以看到数据库连接,点开数据库还可以看到表,如下图:
至此,前面的疑问得到了答案,我们虽然没有为程序创建数据库也没有创建表,但是程序都自动创建好了,并且程序中对数据库表的读写操作也都被存储到数据库中,
保存在何处以及数据库名等我们都了解了。
7、我不想用默认数据库名怎么办?我想要程序连接到其他的数据库,而不是默认visual studio自带的SQL Express 或 LocalDB,要怎么做?
so easy
如果只是想改数据库名,只需给CourseraContext类加个构造方法:public CourseraContext() : base("OceanUniversityCoursea") { },然后运行程序,记得程序运行起来后要操作一下需要读写数据库操作的功能,然后再用上面教的方法去找一下数据库,可以看到自动创建了新的数据库:OceanUniversityCoursea。
如果想把数据库部署到其他地方,可以用配置数据库连接串方式,并且在数据库连接串中可以任意填写数据库名。
首先在程序的App.config配置文件中加上一下代码(server=名称自己改成自己本地数据库的服务名称):
<connectionStrings> <add name="DefaultConnection" providerName="System.Data.SqlClient" connectionString="Server=localhost;Database=Coursera;Trusted_Connection=True;" /> </connectionStrings>
然后把CourseraContext类的构造方法改成:public CourseraContext() : base("DefaultConnection") { }
再次运行程序,记得程序运行起来后要操作一下需要读写数据库操作的功能,打开数据库,可以看到程序自动创建的数据库:Coursea。
8、如果需要对模型类进行修改,删除或增加属性,会不会自动同步到数据库表的字段?
现在需要给Course增加一个Url属性,代码如下:
internal class Course { public int Id { get; set; } public string Name { get; set; } public string Url { get; set; } //新增加的属性 public virtual List<Student> Students { get; set; } }
修改代码后,运行程序,操作一下需要读写数据库的功能,会直接报错:
System.InvalidOperationException:“The model backing the 'CourseraContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).”
原因是我们给Course模型添加属性后,没有同步更新数据库架构。这时需要用到Code First 迁移的功能。只需按下面步骤操作就好:
1)打开 工具-> 库包管理器-> 程序包管理器控制台。
2)在包管理器控制台中运行 Enable-Migrations 命令:
(注:这个指令运行一次就好,如果后面需要再次更改模型类,不需要再执行这个指令)。
运行 Enable-Migrations 命令后,项目根目录会多一个文件夹:Migrations,里面是迁移的文件。
3)在包管理器控制台中运行添加迁移命令 Add-Migration AddCourse_Url :
AddCourse_Url是本次生成迁移的名称,可以自己任意命名。这条命令将检查程序中模型类发生的更改,并生成迁移的代码,以待更新数据库架构时调用。
4)在包管理器控制台中运行更新数据库命令 Update-Database:
这条命令是将上一步添加的迁移同步到目标数据库架构。
完成前面4个步骤后,再运行程序,操作需要读写数据库的功能,可以成功了。如果后面要再修改程序中的模型类,只需要重复步骤3和4就可以了。
9、想让程序每次运行自动更新数据库架构到最新的迁移可以吗?
在程序一开始运行的地方加上这段代码就行了:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<CourseraContext, Configuration>());
10、数据注释
如前面的模型类Student属性FirstName限制最长20个字符:
[MaxLength(20)]
public string FirstName { get; set; }
EF 支持的全部注释列表为:
- KeyAttribute
- StringLengthAttribute
- MaxLengthAttribute
- ConcurrencyCheckAttribute
- requiredattribute
- TimestampAttribute
- ComplexTypeAttribute
- ColumnAttribute
- TableAttribute
- InversePropertyAttribute
- ForeignKeyAttribute
- DatabaseGeneratedAttribute
- NotMappedAttribute
11、Fluent API
除了数据批注外,配置模型的另一种方法是通过 Code First Fluent API。
大多数模型配置可以使用简单的数据批注完成。 Fluent API 是一种更高级的方法,它指定模型配置,该配置涵盖了数据批注可以执行的所有操作以及数据批注无法实现的更高级配置。 数据批注和 Fluent API 可一起使用。
下面展示怎么使用Fluent API:
internal class CourseraContext : DbContext { public CourseraContext() : base("DefaultConnection") { } public DbSet<Course> Courses { get; set; } public DbSet<Student> Students { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //使用Fluent API,将Student的属性LastName长度限制为20字符 //效果和[MaxLength(20)]相同 modelBuilder.Entity<Student>() .Property(u => u.LastName) .HasMaxLength(20); } }
源代码:https://github.com/LuckyDonkey/DotNet_Some_Samples/tree/master/CodeFirstNewDatabaseSample
参考:https://hintdesk.com/2013/07/26/entity-framework-code-first-basic-faq/
https://docs.microsoft.com/zh-cn/ef/ef6/modeling/code-first/workflows/new-database