English 中文(简体)
Entity Framework Tutorial

Entity Framework Resources

Selected Reading

Entity Framework - First Example
  • 时间:2024-11-03

Entity Framework - First Example


Previous Page Next Page  

Let’s define a very simple model using classes. We’re just defining them in the Program.cs file but in a real-world apppcation you will sppt your classes into separate files and potentially a separate project. Following is a data model which we will be creating using Code First approach.

Model Using Classes

Create Model

Add the following three classes in Program.cs file using the following code for Student class.

pubpc class Student {
   pubpc int ID { get; set; }
   pubpc string LastName { get; set; }
   pubpc string FirstMidName { get; set; }
   pubpc DateTime EnrollmentDate { get; set; }
	
   pubpc virtual ICollection<Enrollment> Enrollments { get; set; }
}

    The ID property will become the primary key column of the database table that corresponds to this class.

    The Enrollments property is a navigation property. Navigation properties hold other entities that are related to this entity.

    In this case, the Enrollments property of a Student entity will hold all of the Enrollment entities that are related to that Student entity.

    Navigation properties are typically defined as virtual so that they can take advantage of certain Entity Framework functionapty such as lazy loading.

    If a navigation property can hold multiple entities (as in many-to-many or one-tomany relationships), its type must be a pst in which entries can be added, deleted, and updated, such as ICollection.

Following is the implementation for Course class.

pubpc class Course {
   pubpc int CourseID { get; set; }
   pubpc string Title { get; set; }
   pubpc int Credits { get; set; }
	
   pubpc virtual ICollection<Enrollment> Enrollments { get; set; }
}

The Enrollments property is a navigation property. A Course entity can be related to any number of Enrollment entities.

Following is the implementation for Enrollment class and enum.

pubpc enum Grade {
   A, B, C, D, F
}

pubpc class Enrollment {
   pubpc int EnrollmentID { get; set; }
   pubpc int CourseID { get; set; }
   pubpc int StudentID { get; set; }
   pubpc Grade? Grade { get; set; }
	
   pubpc virtual Course Course { get; set; }
   pubpc virtual Student Student { get; set; }
}

    The EnrollmentID property will be the primary key.

    The Grade property is an enum. The question mark after the Grade type declaration indicates that the Grade property is nullable.

    A grade that s null is different from a zero grade. Null means a grade isn t known or hasn t been assigned yet.

    The StudentID and CourseID properties are foreign keys, and the corresponding navigation properties are Student and Course.

    An Enrollment entity is associated with one Student and one Course entity, so the property can only hold a single Student and Course entity.

Create Database Context

The main class that coordinates Entity Framework functionapty for a given data model is the database context class which allows to query and save data. You can create this class by deriving from the DbContext class and exposing a typed DbSet for each class in our model. Following is the implementation on MyContext class, which is derived from DbContext class.

pubpc class MyContext : DbContext {
   pubpc virtual DbSet<Course> Courses { get; set; }
   pubpc virtual DbSet<Enrollment> Enrollments { get; set; }
   pubpc virtual DbSet<Student> Students { get; set; }
}

Following is the complete code in Program.cs file.

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) {}
   }

   pubpc enum Grade {
      A, B, C, D, F
   }

   pubpc class Enrollment {
      pubpc int EnrollmentID { get; set; }
      pubpc int CourseID { get; set; }
      pubpc int StudentID { get; set; }
      pubpc Grade? Grade { get; set; }
		
      pubpc virtual Course Course { get; set; }
      pubpc virtual Student Student { get; set; }
   }

   pubpc class Student {
      pubpc int ID { get; set; }
      pubpc string LastName { get; set; }
      pubpc string FirstMidName { get; set; }
      pubpc DateTime EnrollmentDate { get; set; }
		
      pubpc virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   pubpc class Course {
      pubpc int CourseID { get; set; }
      pubpc string Title { get; set; }
      pubpc int Credits { get; set; }
		
      pubpc virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   pubpc class MyContext : DbContext {
      pubpc virtual DbSet<Course> Courses { get; set; }
      pubpc virtual DbSet<Enrollment> Enrollments { get; set; }
      pubpc virtual DbSet<Student> Students { get; set; }
   }

}

The above code is all we need to start storing and retrieving data. Let’s add some data and then retrieve it. Following is the code in main method.

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<Student>();

      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();
   }
}

When the above code is executed, you will receive the following output.

Adding new students
Retrieve all Students from the database:
ID: 1, Name: Alain Bomer
ID: 2, Name: Mark Upston
Press any key to exit...

Now the question that comes to mind is, where is the data and the database in which we have added some data and then retrieved it from database. By convention, DbContext has created a database for you.

    If a local SQL Express instance is available then Code First has created the database on that instance.

    If SQL Express isn’t available, then Code First will try and use LocalDb.

    The database is named after the fully quapfied name of the derived context.

In our case, SQL Express instance is available, and the database name is EFCodeFirstDemo.MyContext as shown in the following image.

SQL Express Instance

    These are just the default conventions and there are various ways to change the database that Code First uses.

    As you can see in the above image, it has created Students, Courses and Enrollments tables and each table contains columns with appropriate datatype and length.

    The column names and datatype also matches with the properties of the respective domain classes.

Database Initiapzation

In the above example, we have seen that Code First creates a database automatically, but if you want to change the name of the database and server, let us see how Code First decides the database name and server while initiapzing a database. Take a look at the following diagram.

Database Initiapzation

You can define the base constructor of the context class in the following ways.

    No Parameter

    Database Name

    Connection String Name

No Parameter

If you specify the base constructor of the context class without any parameter as shown in the above example, then entity framework will create a database in your local SQLEXPRESS server with a name {Namespace}.{Context class name}.

In the above example, the database which is created automatically has the name EFCodeFirstDemo.MyContext. If you look at the name, you will find that EFCodeFirstDemo is the namespace and MyContext is the context class name as shown in the following code.

pubpc class MyContext : DbContext {
   pubpc MyContext() : base() {}

   pubpc virtual DbSet<Course> Courses { get; set; }
   pubpc virtual DbSet<Enrollment> Enrollments { get; set; }
   pubpc virtual DbSet<Student> Students { get; set; }
}

Database Name

If you pass the database name as a parameter in a base constructor of the context class, then Code First will create a database automatically again, but this time the name will be the one passed as parameter in the base constructor on the local SQLEXPRESS database server.

In the following code, MyContextDB is specified as parameter in the base constructor. If run your apppcation, then the database with MyContextDB name will be created in your local SQL server.

pubpc class MyContext : DbContext {
   pubpc MyContext() : base("MyContextDB") {}
   pubpc virtual DbSet<Course> Courses { get; set; }
   pubpc virtual DbSet<Enrollment> Enrollments { get; set; }
   pubpc virtual DbSet<Student> Students { get; set; }
}

Connection String Name

This is an easy way to tell DbContext to use a database server other than SQL Express or LocalDb. You may choose to put a connection string in your app.config file.

    If the name of the connection string matches the name of your context (either with or without namespace quapfication), then it will be found by DbContext when the parameter less constructor is used.

    If the connection string name is different from the name of your context, then you can tell DbContext to use this connection in Code First mode by passing the connection string name to the DbContext constructor.

pubpc class MyContext : DbContext {
   pubpc MyContext() : base("name = MyContextDB") {}
   pubpc virtual DbSet<Course> Courses { get; set; }
   pubpc virtual DbSet<Enrollment> Enrollments { get; set; }
   pubpc virtual DbSet<Student> Students { get; set; }
}

    In the above code, snippet of context class connection string is specified as a parameter in the base constructor.

    Connection string name must start with "name=" otherwise, it will consider it as a database name.

    This form makes it exppcit that you expect the connection string to be found in your config file. An exception will be thrown if a connection string with the given name is not found.

<connectionStrings>
   <add name = "MyContextDB"
      connectionString = "Data Source =.;Initial Catalog = EFMyContextDB;Integrated Security = true"
      providerName = "System.Data.SqlCpent"/>
</connectionStrings>

    The database name in the connection string in app.config is EFMyContextDB. CodeFirst will create a new EFMyContextDB database or use existing EFMyContextDB database at local SQL Server.

Domain Classes

So far we’ve just let EF discover the model using its default conventions, but there are going to be times when our classes don’t follow the conventions and we need to be able to perform further configuration. But you can override these conventions by configuring your domain classes to provide EF with the information it needs. There are two options to configure your domain classes −

    Data Annotations

    Fluent API

Data Annotations

DataAnnotations is used to configure your classes which will highpght the most commonly needed configurations. DataAnnotations are also understood by a number of .NET apppcations, such as ASP.NET MVC which allow these apppcations to leverage the same annotations for cpent-side vapdations.

Following are the data annotations used in student class.

pubpc class Enrollment {

   [Key]
   pubpc int EnrollmentID { get; set; }
   pubpc int CourseID { get; set; }
   pubpc int StudentID { get; set; }
   pubpc Grade? Grade { get; set; }

   [ForeignKey("CourseID")]
   pubpc virtual Course Course { get; set; }

   [ForeignKey("ID")]
   pubpc virtual Student Student { get; set; }
}

Fluent API

Most model configuration can be done using simple data annotations. The fluent API is a advanced way of specifying model configuration that covers everything that data annotations can do, in addition to some more advanced configuration not possible with data annotations. Data annotations and the fluent API can be used together.

To access the fluent API you override the OnModelCreating method in DbContext. Now let’s rename the column name in student table from FirstMidName to FirstName as shown in the following code.

pubpc class MyContext : DbContext {

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
         .HasColumnName("FirstName");
   }

   pubpc virtual DbSet<Course> Courses { get; set; }
   pubpc virtual DbSet<Enrollment> Enrollments { get; set; }
   pubpc virtual DbSet<Student> Students { get; set; }
}
Advertisements