This is an extension of a series of articles devoted to developing with the Entity Framework and ASP.NET MVC 3. You can find the first chapters at the following links:
In previous lessons you learned how to work with a simple data model consisting of three entities. In this lesson you will add a few entities and links between them and learn how to work with annotations to manage classes of models.
The result will look like this:

')
Using Attributes to Manage Database Formatting, Validation, and Mapping
In this lesson you will see examples of attributes that you can add to the model classes to control the formatting, validation, and mapping of the database. Then you create a complete School data model by adding attributes to the already created classes and creating new classes for the entity types remaining in the model.
DisplayFormat attribute
For student enrollment dates, all pages now display the time along with the date, whereas we only need the date. With the help of annotations you can specify in one place a setting that will apply to everything. To do this, add an attribute to the EnrollmentDate property in the Student class.
In
Models \ Student . cs add using for System.ComponentModel.DataAnnotations and the DisplayFormat attribute for the EnrollmentDate property:
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace ContosoUniversity.Models { public class Student { public int StudentID { get; set; } public string LastName { get; set; } public string FirstMidName { get; set; } [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)] public DateTime EnrollmentDate { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } } }
The formatting string indicates that you only need to display a short date form of this property. The ApplyFormatInEditMode setting indicates that this formatting should also be applied to the values ​​displayed in text strings intended for editing. (suppose we do not need to display in some fields, for example, which contain currency-related values, a currency sign)
Make sure that the dates are no longer shown on the About and Student pages.

MaxLength attribute
Attributes can be used to define validation rules, for example, if it is necessary to limit the value entered by the user to 50 characters. To take advantage of this feature, add the Range attribute in the LastName and FirstMidName properties:
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace ContosoUniversity.Models { public class Student { public int StudentID { get; set; } [MaxLength(50)] public string LastName { get; set; } [MaxLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")] public string FirstMidName { get; set; } [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)] public DateTime EnrollmentDate { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } } }
If you try to enter a last name of more than 50 characters, a standard error message will be displayed, in a similar case, the name of the error will contain our own error message.
Open the Create page and try entering two names of more than 50 characters, then click Create to make sure that the validation works.

Specifying the maximum value for the input elements is one of the good practices. Otherwise, if the Code First approach is used, the names of the corresponding columns will have the maximum allowable length when creating the database.
Column attribute
Attributes can control the mapping classes to the database. Suppose you used the FirstMidName name for the "First Name" field because this field could also contain a middle name. But you want the corresponding column in the database to be called FirstName, because users use this name in their queries. For this, you can use the Column attribute.
The Column attribute indicates that when creating a database, the column in the Student table that maps to the FirstMidName property will be called FirstName.
Add this attribute to the FirstMidName property:
[Column("FirstName")] public string FirstMidName { get; set; }
Open the Student Index page, where nothing has changed (you need not only to start the site and look at the home page, you must go to the Student Index page to initiate a call to the database, which also initiates its deletion and re-creation). However, if you open the
Server Explorer database you will see that the column in the Student table is called FirstName.

In the
Properties window, you can see that the length is limited to 50 characters using the MaxLength attribute.

Creating an Instructor entity

Create
Models \ Instructor . cs with the following code:
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace ContosoUniversity.Models { public class Instructor { public Int32 InstructorID { get; set; } [Required(ErrorMessage = "Last name is required.")] [Display(Name="Last Name")] [MaxLength(50)] public string LastName { get; set; } [Required(ErrorMessage = "First name is required.")] [Column("FirstName")] [Display(Name = "First Name")] [MaxLength(50)] public string FirstMidName { get; set; } [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)] [Required(ErrorMessage = "Hire date is required.")] [Display(Name = "Hire Date")] public DateTime? HireDate { get; set; } public string FullName { get { return LastName + ", " + FirstMidName; } } public virtual ICollection<Course> Courses { get; set; } public virtual OfficeAssignment OfficeAssignment { get; set; } } }
Notice that some of the properties are similar to the properties of the Student entity. In
Implementing Inheritance, we use inheritance to solve the problem of redundancy.
Attributes Required and Display
Attributes of the LastName property indicate that this is a required value, the caption for the text field should be “Last Name” (instead of the name of the property “LastName”) and the length of the entered value should be no more than 50 characters.
[Required(ErrorMessage = "Last name is required.")] [Display(Name="Last Name")] [MaxLength(50)] public string LastName { get; set; }
Calculated FullName property
FullName is a calculated property that contains a value calculated by combining two other properties. Therefore, it has only an accessor, but the corresponding column is not created in the database.
public string FullName { get { return LastName + ", " + FirstMidName; } }
Navigation Properties Courses and OfficeAssignment
Properties Courses and OfficeAssignment - navigation properties. As mentioned earlier, they are usually marked with the virtual modifier to use lazy loading. In addition, if this property can contain multiple entities, its type should be Icollection.
Since the teacher can conduct several courses, the variable Courses is defined as a collection of entities Course. On the other hand, a teacher can have only one office, so OfficeAsignment is defined as the only entity of the type OfficeAssignment (which can be null if the teacher has no office).
public virtual ICollection<Course> Courses { get; set; } public virtual OfficeAssignment OfficeAssignment { get; set; }
Creating an OfficeAssignment Entity

Create
Models \ OfficeAssignment . cs with the following content:
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace ContosoUniversity.Models { public class OfficeAssignment { [Key] public int InstructorID { get; set; } [MaxLength(50)] [Display(Name = "Office Location")] public string Location { get; set; } public virtual Instructor Instructor { get; set; } } }
Key attribute
A one-to-zero-or-one relationship exists between Instructor entities and OfficeAssignment. The designated office exists only in conjunction with the designated teacher, so its primary key is also a foreign key to the Instructor entity. The Entity Framework, however, cannot automatically recognize the InstructorID as a primary key because the name of this property does not comply with the primary key naming conventions, not equal to the ID and classnameID. Therefore, the Key attribute indicates that this attribute is the primary key.
[Key] public int InstructorID { get; set; }
The Key attribute can also be used for the situation where you already have a primary key, but you want to name the property other than
classname ID or ID.
Instructor Navigation Property
The essence of the Instructor is a nullable Office Assignment navigation property (the teacher may not have an office), and the essence of the Office Assignment is a non-nullable Instructor navigation property (the office cannot exist without a teacher). When Instructor has an OfficeAsignment entity associated with it, both have links to each other in their navigation property.
To be continued…Acknowledgments
Thanks for the help in the translation of Alexander Belotserkovsky (
ahriman ).