EntityFramework_MVC4中EF5 新手入门教程之四 ---4.在EF中创建更复杂的数据模型
在以前的教程你曾与一个简单的数据模型,由三个实体组成。在本教程中,您将添加更多的实体和关系,并通过指定格式、 验证和数据库映射规则,您将自定义数据模型。你会看到自定义的数据模型的两种方式: 通过添加属性,实体类并通过将代码添加到数据库上下文类。
当您完成时,实体类将已完成的数据模型中,如下图所示:
通过使用属性进行自定义的数据模型
在本节中,您会看到如何通过使用指定的格式,验证和数据库映射规则的属性来自定义数据模型。然后在以下各节,您将创建的几个完整的School
数据模型,通过添加属性的类已创建,并在模型中创建新的类,其余的实体类型。
数据类型属性
对于学生入学日期,所有 web 页当前显示的时间以及日期,虽然所有你关心为此字段是日期。通过使用数据批注属性,可以让一个代码将修复中每个视图用于显示数据的显示格式的更改。若要查看示例如何去做你会将属性添加到Student
班级中的EnrollmentDate
属性。
在Models\Student.cs,添加System.ComponentModel.DataAnnotations
命名空间的using
语句和DataType
和DisplayFormat
属性添加的EnrollmentDate
属性,如下面的示例所示:
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; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
}
数据类型属性用来指定比数据库内部类型更加具体的数据类型。在这种情况下,我们只想要跟踪的日期,不是日期和时间。数据类型枚举提供多种数据类型例如日期、 时间、 电话号码、 货币、 电子邮件地址和更多。DataType
属性,还可以启用应用程序以自动提供特定于类型的功能。例如, mailto:
的DataType.EmailAddress,可以创建链接和一个日期选择器可供DataType.Date支持HTML5的浏览器。数据类型属性发出 HTML 5 的浏览器能理解的 HTML 5数据-(发音为数据短划线) 属性。数据类型属性不提供任何验证。
DataType.Date
不指定显示日期的格式。默认情况下,根据基于服务器的CultureInfo的默认格式显示的数据字段.
DisplayFormat
属性用于显式指定的日期格式:
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }
ApplyFormatInEditMode
设置指定的值显示在文本框中进行编辑时,应该也适用已指定的格式。(您可能不希望一些领域 — — 例如,对于货币值,您可能不希望货币符号在文本框中编辑。)
你可以使用DisplayFormat属性本身,但它通常是一个好的主意,也使用该数据类型的属性。DataType
属性传递语义的而不是如何呈现在屏幕上,数据和提供以下好处,你不要跟DisplayFormat
:
- 浏览器可以启用 HTML5 功能 (例如,显示一个日历控件、 适当的区域设置的货币符号、 电子邮件的链接等。)。
- 默认情况下,浏览器将呈现使用基于您的区域设置的正确格式的数据.
- 数据类型属性可以启用 MVC 选择权字段模板来呈现的数据 (如果使用了DisplayFormat使用字符串模板)。有关详细信息,请参阅布拉德 · Wilson ASP.NET MVC 2 模板。(虽然为 MVC 2 写,这篇文章仍适用于当前版本的 ASP.NET MVC。)
如果您使用日期字段的DataType
属性,您必须也指定 DisplayFormat
属性,以确保该字段在 Chrome 浏览器中都能正确呈现。更多的信息,请参阅此计算器线程.
再次运行学生索引页,并注意时间将不再显示在注册日期。同样会适用于任何使用Student
模型的视图。
StringLengthAttribute
您还可以指定数据验证规则并使用属性的消息。假设您想要确保用户不输入超过 50 个字符的名称。若要添加此限制,请将StringLength属性添加到LastName
和FirstMidName
的属性,如下面的示例所示:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace ContosoUniversity.Models
{
public class Student
{
public int StudentID { get; set; }
[StringLength(50)]
public string LastName { get; set; }
[StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]
public string FirstMidName { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
}
StringLength属性不会防止用户空白输入一个名称。可以使用正则表达式属性应用到输入的限制。例如,下面的代码需要的第一个字符是大写,将其余的字符,要按字母顺序排列:
[RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")]
MaxLength属性提供类似的功能,到StringLength属性,但不提供客户端验证。
运行应用程序并单击学生选项卡。您收到以下错误:
自创建数据库,支持 'SchoolContext' 上下文模型已更改。请考虑使用代码第一次迁移来更新数据库 (http://go.microsoft.com/fwlink/?LinkId=238269).
数据库模型已更改,必须在数据库架构中,改变的方式,实体框架检测到。您将使用迁移来更新架构,而不会丢失任何数据,您添加到数据库中使用的 UI。如果您更改由Seed
方法创建的数据,这将更改回其原始状态的AddOrUpdate方法,您使用Seed
法。(AddOrUpdate是等同于"upsert"操作从数据库术语。
在程序包管理器控制台 (PMC) 中,输入以下命令:
一个dd-migration MaxLengthOnNames
update-database
add-migration MaxLengthOnNames
命令创建一个名为< 时间戳 > _MaxLengthOnNames.cs文件。此文件包含将更新数据库,以匹配当前的数据模型的代码。实体框架规定为迁移文件名称预先使用的时间戳用于命令迁移的方法。如果您删除数据库,创建多个迁移后或使用迁移部署项目,所有的迁移应用他们被创建的顺序。
运行创建页上,并输入任一超过 50 个字符的名称。只要你超过 50 个字符,客户端验证可以立即显示一条错误消息。
列属性
此外可以使用属性来控制如何将您的类和属性映射到数据库。假设您已经使用名称FirstMidName
为第一个名称字段,因为该字段可能还包含一个中间名。但你想要的数据库列被命名为FirstName
,因为将会写对数据库的临时查询的用户已经习惯了这个名字。若要使这种映射,可以使用Column
属性。
Column
属性指定当创建数据库时,映射到FirstMidName
属性的Student
表中的列将被命名为FirstName
。换句话说,当您的代码引用Student.FirstMidName
,数据将来自或在Student
表的FirstName
列中进行更新。如果您不指定列名称,则会给属性名称相同的名称。
添加一条 using 声明为System.ComponentModel.DataAnnotations.Schema和列名称归因于FirstMidName
属性中,以下突出显示的代码所示:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ContosoUniversity.Models
{
public class Student
{
public int StudentID { get; set; }
[StringLength(50)]
public string LastName { get; set; }
[StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]
[Column("FirstName")]
public string FirstMidName { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
}
如何添加列属性更改支持 SchoolContext,所以它不会匹配数据库的模型。在 PMC 打造另一次迁移中输入以下命令:
add-migration ColumnFirstName
update-database
在服务器资源管理器(数据库资源管理器如果您正在使用 Web 快递),双击的学生表。
下图显示了原始的列名称,它正如你在应用前两个迁移之前。除了从FirstMidName
更改为FirstName
列名称,两个名称列已从MAX
长度为 50 个字符。
此外可以使数据库映射更改使用Fluent API,您将看到在本教程后面。
注如果你尝试编译在您完成所有这些实体类的创建之前,你可能会得到编译器错误。
创建讲师实体
创建Models\Instructor.cs,模板代码替换为以下代码:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ContosoUniversity.Models
{
public class Instructor
{
public int InstructorID { get; set; }
[Required]
[Display(Name = "Last Name")]
[StringLength(50)]
public string LastName { get; set; }
[Required]
[Column("FirstName")]
[Display(Name = "First Name")]
[StringLength(50)]
public string FirstMidName { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Hire Date")]
public DateTime HireDate { get; set; }
public string FullName
{
get { return LastName + ", " + FirstMidName; }
}
public virtual ICollection<Course> Courses { get; set; }