📅  最后修改于: 2020-11-21 07:32:19             🧑  作者: Mango
让我们使用类定义一个非常简单的模型。我们只是在Program.cs文件中定义它们,但是在实际应用程序中,您将把类分为单独的文件和可能的单独项目。以下是我们将使用代码优先方法创建的数据模型。
使用下面的学生类代码在Program.cs文件中添加以下三个类。
public class Student {
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection Enrollments { get; set; }
}
ID属性将成为对应于此类的数据库表的主键列。
登记属性是导航属性。导航属性包含与此实体相关的其他实体。
在这种情况下,学生实体的“注册”属性将保存与该学生实体相关的所有注册实体。
导航属性通常定义为虚拟的,以便它们可以利用某些Entity Framework功能,例如延迟加载。
如果导航属性可以容纳多个实体(如多对多或一对多关系),则其类型必须是一个列表,可以在其中添加,删除和更新条目,例如ICollection。
以下是课程课程的实现。
public class Course {
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection Enrollments { get; set; }
}
登记属性是导航属性。课程实体可以与任意数量的注册实体相关。
以下是Enrollment类和枚举的实现。
public enum Grade {
A, B, C, D, F
}
public class Enrollment {
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
EnrollmentID属性将为主键。
Grade属性是一个枚举。成绩类型声明后的问号表示成绩属性为可空。
空等级与零等级不同。 Null表示等级未知或尚未分配。
StudentID和CourseID属性是外键,相应的导航属性是Student和Course。
一个注册实体与一个学生和一个课程实体相关联,因此该资源只能容纳一个学生和课程实体。
协调给定数据模型的Entity Framework功能的主要类是数据库上下文类,它允许查询和保存数据。您可以通过派生DbContext类并公开类型化的DbSet来创建此类。
public class MyContext : DbContext {
public virtual DbSet Courses { get; set; }
public virtual DbSet Enrollments { get; set; }
public virtual DbSet Students { get; set; }
}
以下是Program.cs文件中的完整代码。
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFCodeFirstDemo {
class Program {
static void Main(string[] args) {}
}
public enum Grade {
A, B, C, D, F
}
public class Enrollment {
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
public class Student {
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection Enrollments { get; set; }
}
public class Course {
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection Enrollments { get; set; }
}
public class MyContext : DbContext {
public virtual DbSet Courses { get; set; }
public virtual DbSet Enrollments { get; set; }
public virtual DbSet Students { get; set; }
}
}
上面的代码是我们开始存储和检索数据所需的全部。让我们添加一些数据,然后检索它。以下是main方法中的代码。
static void Main(string[] args) {
using (var context = new MyContext()) {
// Create and save a new Students
Console.WriteLine("Adding new students");
var student = new Student {
FirstMidName = "Alain", LastName = "Bomer",
EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
};
context.Students.Add(student);
var student1 = new Student {
FirstMidName = "Mark", LastName = "Upston",
EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
};
context.Students.Add(student1);
context.SaveChanges();
// Display all Students from the database
var students = (from s in context.Students
orderby s.FirstMidName select s).ToList();
Console.WriteLine("Retrieve all Students from the database:");
foreach (var stdnt in students) {
string name = stdnt.FirstMidName + " " + stdnt.LastName;
Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
执行上述代码后,您将收到以下输出。
Adding new students
Retrieve all Students from the database:
ID: 1, Name: Alain Bomer
ID: 2, Name: Mark Upston
Press any key to exit...
现在想到的问题是,数据和数据库在哪里,我们在其中添加了一些数据,然后从数据库中检索了这些数据。按照约定,DbContext为您创建了一个数据库。
如果本地SQL Express实例可用,则Code First已在该实例上创建数据库。
如果没有SQL Express,则Code First将尝试并使用LocalDb。
数据库以派生上下文的完全限定名称命名。
在我们的示例中,SQL Express实例可用,数据库名称为EFCodeFirstDemo.MyContext,如下图所示。
这些只是默认约定,并且有多种方法可以更改Code First使用的数据库。
如上图所示,它已经创建了“学生”,“课程”和“注册”表,并且每个表都包含具有适当数据类型和长度的列。
列名和数据类型也与相应域类的属性匹配。
在上面的示例中,我们已经看到Code First自动创建一个数据库,但是如果您想更改数据库和服务器的名称,让我们看看Code First在初始化数据库时如何确定数据库名称和服务器。看下图。
您可以通过以下方式定义上下文类的基本构造函数。
如果如上例所示,指定上下文类的基本构造函数而没有任何参数,则实体框架将在本地SQLEXPRESS服务器中创建一个名称为{Namespace}。{Context class name}的数据库。
在上面的示例中,自动创建的数据库的名称为EFCodeFirstDemo.MyContext。如果查看该名称,则会发现EFCodeFirstDemo是名称空间,而MyContext是上下文类名称,如以下代码所示。
public class MyContext : DbContext {
public MyContext() : base() {}
public virtual DbSet Courses { get; set; }
public virtual DbSet Enrollments { get; set; }
public virtual DbSet Students { get; set; }
}
如果在上下文类的基本构造函数中将数据库名称作为参数传递,则Code First将再次自动创建一个数据库,但是这次名称将是在本地SQLEXPRESS数据库服务器上的基本构造函数中作为参数传递的名称。 。
在以下代码中,将MyContextDB指定为基本构造函数中的参数。如果运行您的应用程序,则将在本地SQL服务器中创建具有MyContextDB名称的数据库。
public class MyContext : DbContext {
public MyContext() : base("MyContextDB") {}
public virtual DbSet Courses { get; set; }
public virtual DbSet Enrollments { get; set; }
public virtual DbSet Students { get; set; }
}
这是告诉DbContext使用SQL Express或LocalDb以外的数据库服务器的简便方法。您可以选择将连接字符串放入app.config文件中。
如果连接字符串的名称与您的上下文的名称匹配(具有或不具有名称空间限定),则当使用参数less构造函数时,DbContext将找到它。
如果连接字符串名称与您的上下文名称不同,则可以通过将连接字符串名称传递给DbContext构造函数来告诉DbContext在“代码优先”模式下使用此连接。
public class MyContext : DbContext {
public MyContext() : base("name = MyContextDB") {}
public virtual DbSet Courses { get; set; }
public virtual DbSet Enrollments { get; set; }
public virtual DbSet Students { get; set; }
}
在上面的代码中,上下文类连接字符串的片段被指定为基本构造函数中的参数。
连接字符串名称必须以“ name =”开头,否则,它将被视为数据库名称。
这种形式表明您希望在配置文件中找到连接字符串。如果找不到具有给定名称的连接字符串,则将引发异常。
app.config中的连接字符串中的数据库名称为EFMyContextDB 。 CodeFirst将在本地SQL Server上创建一个新的EFMyContextDB数据库或使用现有的EFMyContextDB数据库。
到目前为止,我们只是让EF使用其默认约定来发现模型,但是有时候我们的类不遵循约定,我们需要能够执行进一步的配置。但是您可以通过配置域类为EF提供所需的信息来覆盖这些约定。有两个选项来配置您的域类-
DataAnnotations用于配置您的类,该类将突出显示最常用的配置。许多.NET应用程序(例如ASP.NET MVC)也可以理解DataAnnotations,这些应用程序允许这些应用程序利用相同的注释进行客户端验证。
以下是学生课堂中使用的数据注释。
public class Enrollment {
[Key]
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
[ForeignKey("CourseID")]
public virtual Course Course { get; set; }
[ForeignKey("ID")]
public virtual Student Student { get; set; }
}
大多数模型配置可以使用简单的数据注释完成。流畅的API是一种指定模型配置的高级方法,该模型配置涵盖了数据注释可以完成的所有工作,以及一些数据注释无法实现的高级配置。数据注释和流利的API可以一起使用。
要访问流利的API,您可以在DbContext中重写OnModelCreating方法。现在,让我们将学生表中的列名从FirstMidName重命名为FirstName,如以下代码所示。
public class MyContext : DbContext {
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity().Property(s ⇒ s.FirstMidName)
.HasColumnName("FirstName");
}
public virtual DbSet Courses { get; set; }
public virtual DbSet Enrollments { get; set; }
public virtual DbSet Students { get; set; }
}