《转》Model First

我们将开始于BAGA业务域的一个小片断:包括我们旅行的目的地和我们的奇客们在这次旅行的住所。

Code First的美妙在于域类的定义代码与EF数据模型所依赖的代码是一样的。我们只需要开始于代码就可以了,例2-1,分别展示了Destination类和Loadging类。在开始的案例中,我们要保持类的简洁;这些类包含了一些自动属性,并没有什么逻辑。

Example 2-1. The domain model

publicclassDestination

{

publicint DestinationId { get; set; }

publicstring Name { get; set; }

publicstring Country { get; set; }

publicstring Description { get; set; }

publicbyte[] Photo { get; set; }

public List<Lodging> Lodgings { get; set; }

}

publicclassLodging

{

publicint LodgingId { get; set; }

publicstring Name { get; set; }

publicstring Owner { get; set; }

publicbool IsResort { get; set; }

public Destination Destination { get; set; }

}

Destination类描述了一个特定的BAGA旅行的目的地,对于任何给定的目的地,从Aspen到Zimbabwe,BAGA都会安排各种住所,从床位到五星级酒店,以便到时暂住。因此目的地对象要包含一个或多个居所,使用了List<lodging>来表达;

EF域类介绍

本质上,这些类与EF和Code First无关。这里只简单描述了域的一部分。

为了让EF框架能够找到这些类,需要使用EF框架的context来服务、管理和持久化数据至数据库。EF框架有两种context工具可供选择,一个是ObjectContext,这一工具从EF第一次发布就一直是EF框架的一部分,而随着EF4.1的发布,伴随Code First推出轻量级的DbContext。两种工具都可选用,但更通用(推荐)的是使用新的DbContext,也就是我们马上就要使用的。本书第7章,你将会学习如何使用ObjectContex进行Code First.

我们的BreakAwayContext类,就继承自DbContext,可以获得DbContext的所有功能。除此以外,还需要返回Destination类和Lodging类的可查询数据集DbSets,以暴露类中的属性

Example 2-2 The BreakAwayContext class

publicclassBreakAwayContext : DbContext

{

public DbSet<Destination> Destinations { get; set; }

public DbSet<Lodging> Lodgings { get; set; }

}

这个小小的类就代表了你在应用程序中使用的完整的数据层.感谢DbContext,你可查询,修改,跟踪和保存目的地和住所数据.下面创建一个控制台程序使用这个数据层来做一些工作,你会看到我们并非言过其实.

将片断放入程序中

为了查看有关行为,下面将带您实现一个小的VS解决方案,在此你可将这些类放进去,然后创建一个简单的控制台程序来测试你的新数据层.确保你已经开始了正确的路径,本示例将把应用程序的各个层组织在不同的项目中.

1.在VS中创建一个新的解决方案;

2.添加一个类库项目到解决方案,命名为Model.

3.在这个项目里,添加一个新的类命名为Destination.

4.修改Destination类以使其与例2-3一致:

Example 2-3. The Destination class

using System.Collections.Generic;

namespace Model

{

publicclassDestination

{

publicint DestinationId { get; set; }

publicstring Name { get; set; }

publicstring Country { get; set; }

publicstring Description { get; set; }

publicbyte[] Photo { get; set; }

publicList<Lodging> Lodgings { get; set; }

}

}

5.添加另一个类,命名为Lodging,使其与例2-4一致.

Example2-4.The Lodging class

namespace Model

{

publicclassLodging

{

publicint LodgingId { get; set; }

publicstring Name { get; set; }

publicstring Owner { get; set; }

publicbool IsResort { get; set; }

public Destination Destination { get; set; }

}

}

这就是Model项目的内容.现在,转到数据层,因为域类尚未连接到EF框架上,我们数据层将完全依赖于EF框架.

小贴士:将NuGet安装到VS中就可以将类库方便地添加到项目中.在第1章您已学到EF可以通过NuGet获取.为了完成如下步骤,你需要为VS安装NuGet扩展.为了安装NuGet,选择工具--扩展管理….会出现扩展管理对话框,然后查找NuGet.选择NuGet扩展管理包,点击下载按钮,按照提示安装.

一旦安装完成,您就可以以一种新的方式使用VS了.你可通过VS的工具菜单--添加类库来添加所需的类库,另一种方式是使用上下文菜单来添加,方法是在解决方案的指定项目上点击右键.在下面的操作步骤中,我们使用后者

1.添加另一个类库项目,命名为DataAcess;

2.在项目资源管理器中右键单击新建立的项目选择"Add Livray Package Reference"

3.在弹出的对话框中,选择Online,并搜索Entity Framework;

4.在EF安装包上点击安装按钮,这将把Code First的运行时组件(EntityFramework.dll)添加到你的项目中;

5.右键单击新的项目并选择添加引用;

6.选择项目选项卡将Model proect加入.这将会使context能够访问刚刚在Model Project上创建的域类;

7.添加一个新类,BreakAwayContext到项目中;

8.配置这个新类如代码2-5;

Example 2-5. The BreakAwayContext class

using System.Data.Entity;

using Model;

namespace DataAccess

{

publicclassBreakAwayContext : DbContext

{

public DbSet<Destination> Destinations { get; set; }

public DbSet<Lodging> Lodgings { get; set; }

}

}

注意类顶部的using语句.一个是System.Data.Entity命名空间.这个命名空间使得你可以访问DbContext和DbSet类;这可能有些令人困惑,命名空间为EntityFramework.dll的程序集是 EntityFramework.dll,而不是System.Data.Entity.dll。System.Data.Entity.dll包含了EF框架的核心,已经是.Net框架的一部分.

现在你的数据访问层已经建好了.可以测试你的数据访问层了.

请等一下,我们还没有告诉数据访问层数据库在哪.还没有连接字符串,没有配置文件,没有关联的数据库.我们要在此利用Code First的第一个功能,数据库初始化.Code First有一系列的步骤来找到数据库并且初始化它.我们现在先使用默认行为,在后面第6章,将会学到更多关于数据库初始化的知识。当然,也可以开始于一个现存的数据库,只是我们现在不这么做。

1.添加一个新的控制台应用程序项目到解决方案,命名为BreakAwayConsole.

2.右键单击新的项目,设置为启动项目;

3.右键单击项目,选择添加类库引用,添加对EF框架的引用;

4.再次右键单击项目,选择添加引用,将Model和DataAcess项目添加至项目;

5.在新项目中,打开Program类;

6.添加两个using语句在文件顶部:

using Model;

using DataAccess;

7.在类中添加一个方法,命名为InsertDestination(代码2-6);

Example 2-6 The InsertDestination Methoed

privatestaticvoid InsertDestination()

{

var destination = new Destination

{

Country = "Indonesia",

Description = "EcoTourism at its best in exquisite Bali",

Name = "Bali"

};

using (var context = new BreakAwayContext())

{

context.Destinations.Add(destination);

context.SaveChanges();

}

}

8.在类中调用这个方法(代码2-7)

Example 2-7. Calling the InsertDestination method

staticvoid Main()

{

InsertDestination();

}

完成!对这两个域类你只用了少量代码,两行数据访问类以及这个小的应用类,你已经开始准备运行应用程序了。

这个控制台程序并不会显示任何信息.有趣的是发生数据库里的事情:数据库刚才并不存在。

Code First 通过检视Destination 和 Lodging 类确定了数据模型,然后根据类属性推断出数据库的架构模型.既然我们没有提供连接字符串,它就使用默认的约定,查找本地SQL Server Express实例(localhost\SQLEXPERSS)作为数据库宿主,然后以context类的类名DataAcess.BreakAwayContext匹配数据库名.没有找到这样的数据库,Code First就创建它,然后使用它在模型中发现的类依据约定创建表和表的字段。

我们来看看SQL Server Express中Code First创建的数据库(图2-1).

可以看到,DataAccess.BreakAwayContext 有三个表:Destinations ,Lodgings和EdmMetadata,后者用于Code First的数据库初始化,后面我们会提到.

关于表,构架,和字段名的约定

Code First 约定表名使用EF框架的复数化服务(由EF4引入),即使用英语语法的类名复数形式来命名表名。(这个功能可以关闭,见第7章,译者注)默认情况下,每个表都使用dbo构架创建。Code First 属性映射的列使用与类中属性一致的名字命名.

关于主键的约定

再次观察数据库表,你会找到Code First已经使用的默认规则。例如,Code First知道Detination类的DestinationId和Lodging类的LodgingId意思是键值,然后将这些键映射为数据库的主键。注意这些键都是非空主键(PK,notnull)。Code First默认约定将命名为Id或[类名]Id的属性视为类的键。DestinationId 和LodgingId显然符合这一规则。由于这些属性都是整型类型,Code First还会将它们配置为数据库的标识字段。这表示在插入数据时数据库会为这一字段自动生成值。

字符串属性的约定

字符串约定为映射到不限长度的非空列中。由数据库引擎来负责确定映射到何种类型。对于SQL Server而言,默认数据类型为nvarchar(max)。这就是你在图2-1看到的所有的字符串属性都映射成了nvarchar(max)列的缘故---Destination.Name,Country,Description等等.--同时还允许存储空值;

针对Byte数组的约定

Destination类有一个Photo属性,定义为byte[].Code First 约定byte数组映射到不限长度的非空列中.对SQL Server而言就是varbinary(max)类型.

布尔值的约定

Lodging类中的IsResort属性是一个bool类型.由于bool是一个值类型,不能分配给其一个null值.Code First强制要求此列不能为空.对SQL Server而言将bool属性映射为bit 数的库类型.

一对多关系的约定

一个目的地会有很多居所,因此Destination类有一个List<Lodging>属性允许你获取特定目的地的所有居所信息.同时,Lodging类也有一个Destination类型的属性,,因此你可看到某一居所与某一特定的目的地相连接.Code First将这种情况视为一对多关系,约定Lodging表有一个外键约束目的地与居所间的所有关系.

注意尽管在Lodging类中没有外键属性指向Destination类(如DestinationId),Code First仍然使用默认规则创建了一个,形如[Name of navigation property]_[Primary Key of related class](即Destination_DestinationId),这是Code First所为。使得EF框架知道在从数据库中查询或保存时要使用外键.

在目的地和住宿类提供给Code First的导航属性不是一个,而是两个。如果我们只提供了其中之一,关系仍然明显,Code First还是会在数据库中创建外键。还有很多提供外键的约定适用于某些场景,如多对多关系等,在后面我们会深入讨论。

使用配置来覆写约定

正如在第1章学到的,Code First允许你覆写约定,方法是添加配置.可以选择使用Data Annotation的特性标记也可以使用强类型的Fluent API来配置.

您提供的任何配置将会作为模型的一部分,EF框架使用此模型在运行时解析数据。这不仅影响数据库构架,也会影响DbContext内置的验证功能。例如,如果你告诉Code First一个属性是必备的,验证API将让你知道,如果该属性没有被填充的后果。在后续我们将看到这一行为。

Data Annotations是最简单的配置方式,直接应用到你的类和类属性上。这些特性位于System.ComponentModel.DataAnnotations命名空间,目前分布在System.ComponentModel.DataAnnotations.dll和EntityFramework.dll两个程序集中。在未来版本的.NET Framework中,EntityFramework.dll中的Annotations将迁移到System.ComponentModel.DataAnnotations.dll。所以需要在域类的项目中引用上述程序集(取决于您使用的Annotations)。注意Data Annotations能够完成常用的配置,但并非所有Code First配置都可以使用Data Annotation来完成。一些情况下只能使用另一种风格的配置方式:Fluent API。

因为Code First没有自动发现Destination和Lodging类中的某些意图,需要用一些Data Annotations提供额外的配置细节。

小贴士:在C#和Visual Basic应用特性

如果你第一次使用特性,在C#中,特性应使用方括号。例如,使用Annotation 特性Key,在c#中使用[Key],而在Visual Basic中,使用尖括号(<Key>)。当一个特性使用参数时,在C#中是表达了一个等号表达([Table(Schema="baga")]),而Visual Basic使用冒号等号表示(<Table(Schema:="baga")>) 要知道.NET代码中使用特性的更多信息,请参阅MSDN主题"应用特性",在http://msdn.microsoft.com/en-us/library/bfz783fz.aspx。

让我们从Destination类开始.关于这个类我想要作三个调整:

  • 必须提供目的地的名字
  • 限制描述字段的文本内容在500个字符以内
  • 保存照片到SQL Server数据库应为image类型,而不是varbinary(max).

上述需要的Data Annotations特性有两个包含在System.ComponentModel.DataAnnotations.dll程序集中,这是.Net 4的一部分,有一个包含在EntityFramework.dll程序集里,所以需要对两个程序集都要添加引用:

1.在Model项目中,添加对System.ComponentModel.DataAnnotations 程序集的引用.

2.通过类库包装引用添加对EntityFramework程序集的引用.

记住:你必须对每个项目都运行NuGet类库添加向导,即使类库包已经添加到解决方案中的某个项目中.使用同样的步骤将EntityFramework.dll添加到DataAccess项目中.

3.在Destination类顶部,添加System.ComponentModel.DataAnnotations命名空间.

4.修改类如代码2-8所示Example 2-8. Modified Destination class

using System.Collections.Generic;

using System.ComponentModel.DataAnnotations;

namespace Model

{

publicclassDestination

{

publicint DestinationId { get; set; }

[Required]

publicstring Name { get; set; }

publicstring Country { get; set; }

[MaxLength(500)]

publicstring Description { get; set; }

[Column(TypeName = "image")]

publicbyte[] Photo { get; set; }

publicList<Lodging> Lodgings { get; set; }

}

}

Required特性标记不需要附加信息,而MaxLength和Column特性均需要提供参数.这些参数对如何映射到数据库的列进行了明确。我们想要图片储存在SQL Server的image字段里.

小贴士:只要有可能强制将数据库中字段的类型设定为指定类型(例如将byte[]强制指定为image),你可配置数据类型特性。所有的三个特性将会影响数据库的构架,其中之二,Required和MaxLength,也被用于EF框架的验证之用.在观察效果之前,也对Lodging类作些类似的修改.

Annotation特性标记可组合使用,也就是在一个类或属性上可以附加多个annotations特性.我们准备在Lodging.Name属性附加多个配置特性.

添加下述三个注解到Lodging类的Name属性:

[Required]

[MaxLength(200)]

[MinLength(10)]

MinLenght是一个有趣的annotation特性.MaxLength在数据库有对应的含义,而MinLength并不有.MinLength将会用于EF框架的验证,并不会影响数据库.

MinLength只能通过Data Annotations来进行配置,在Fluent API 中无对应项.

理解模型变化如何影响数据库初始化

如果再次运行控制台程序,你会得到一个InvalidOperationException异常.我们刚刚对模型作的修改并没有什么错误,问题在于Code First数据库初始化的默认行为.因此我们需要在继续探索配置时需要修复这些问题.

下面是异常的信息:

The model backing the ‘BreakAwayContext‘ context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the DropCreateDatabaseIfModelChangesstrategy will automatically delete and recreate the database, and optionally seed it with new data.

自上次数据库创建以来,‘BreakAwayContext‘的上下文已经发生变化.要么手工删除或更新数据库,要么调用IDatabaseInitializer接口的实例 Database.SetInitializer.例如 DropCreateDatabaseIfModelChanges策略将自动删除和再创建数据库,并且可选择使用新数据作为种子.

.默认情况下,Code First只有当数据库不存在的时才创建数据库,但目前数据库已经有了,该怎么办呢?

是否还记得EdmMetadata表?如果没有,回头看一下图2-1.这个表包含了Cord First创建数据模型的部分快照。默认情况下,它会伴随着Code First第一次使用模型建立数据库时创建。然后它就会将表中的版本信息与内存中的模型相比较(这可以从EdmMetadata表中读出)。当Code First识别到上一模型的元数据模型与新建立的模型不匹配,就无法将模型映射到数据库.

您有很多选择.一个是简单删除数据库(包括其中的所有数据),然后让Code First使用默认规则(无数据库--创建新数据库)来使用更新模型创建数据库.这可能很痛苦,特别是你在开发过程中,可能会遇到某些情况导致文件锁定而无法删除.另一种方法,我们马上要用,Code First在遇到模型变化时有一套初始化策略可供使用,该行为删除数据库并重建,默认是封装在名为CreateDatabaseIfNotExists的类中,你可告知正在执行中的程序(本处是指控制台程序)使用哪个策略。

修改Main方法使之与例2-9一样.也需要在添加一个using语句,引用System.Data.Entity.

Example 2-9. Adding Database Initialization to the Main method

staticvoid Main(string[] args)

{

Database.SetInitializer(

new DropCreateDatabaseIfModelChanges<BreakAwayContext>());

InsertDestination();

}

在此代码中我告诉Code First使用初始化器并且指定使用何种策略.(这里使用了DropCreateDatabaseIfModelChanges)应用于上下文(BrakAwayCOntext).现在当你返回应用程序,Code First将识别新旧模型的区别,通知初始化器,删除和重建数据库.

如果你已经在其他地方打开了数据库表读取数据,(例如,在Visual Studio的服务器资源管理器),Code First将不能够删除数据库。在这种情况下,在EF框架尝试删除时会有一个延迟,最终因为无法删除而抛出一个异常。似乎这样做太繁琐,特别是当我在用户组和会议展示时。我遇到的一个常见的场景是,我已打开了SQL Server Management Studio(SSMS)中,对数据库进行一些查询。你不得不关闭SSMS的数据库完全释放对数据库的锁定。

Destination类之Destinations表有三个可见的改变,Name设定为必须,在数据库表现为非空字段.Description现在是nvarchar(500)而不再是max,Photo也已经是一个image数据类型.Lodging表也得到影响,Name现在限制为200个字符且为非空型,第三个annotation:MinLength在数据库构架中没有等效值,因此在此忽略.但是,EF框架将会对此进行验证.

Data Annotations和前端验证提示

NET 4中引入的Data Annotations,可以用于ASP.NET(含.Net MVC)作为用户界面的动态数据验证工具来使用。许多Code First 使用的annotations特性标记都来自源于System.ComponentModel.DataAnnotations程序集。因此,这些数据验证功能是.Net程序集的的内置特性。

例如,"Required"特性在.NET4的程序集中,而不在EntityFramework.dll程序集里。因此,如果你在MVC应用程序中使用的Code First类,并且忽略填写一个必须输入的属性,MVC用户界面验证会响应,你可以在图2-3看到。

DbContext还提供了一个验证API,具有服务器端验证的能力,这与使用Data Annotations特性标识还是使用Fluent API来配置类是没有关系的。但是,使用Data Annotations时,MVC与特性更好地配合,实现一些验证API的功能。验证API的细节内容不包括在这本书中,本书的重点在于Code First建模,你可在另一本书:Entity Framework:DbContext找到与验证API有关的信息。

使用Fluent API 配置Code First

使用Data Annotations配置很简单,也可能是你想要的。但是Data Annotations只能获得一部分配置的功能。这时,Fluent API可以提供更多的功能,基于这个原因你可能会愿意用它.

小贴士:Fluent API是什么?

Fluent API并非专用于Code First或EF框架。Fluent API的基本思路是使用链方法调用程序代码,这样代码很容易被开发者所阅读。每一个调用的返回类型都定义为下个调用的有效方法.例如,在Code First的Fluent API中,你可以使用Entity方法选择一个实体来配置.智能感知将会显示出所可以用来配置的方法.如果你使用属性方法选择属性来配置,你就看到所有为特定属性所配置的方法.

还有另一个原因解释为什么开发者首选Fluent API。在将标记应用到你的美妙域类上时,需要定义越来越多的烦人的标记。目前还只是一些验证逻辑,当你学到更多Data Annotations配置特性的时候,你就会发现需要更多的信息指导类如何映射到数据库。如果你喜欢清洁的类,不想让类包含那么多的标记,就可以选择Fluent API。Code First的一个优势就是能够使用自己的类构建EF框架,一个充斥着数据库表名或列类型的类显然不够简洁,Fluent API解决了这一问题,我们来看这是如何实现的。

小贴士:跟随Data Annotations还是跟随Fluent API ?

在本书后续内容中,你将会看到很多例子来说明如何配置映射,有Data Annotations的,也有使用Fluent API的.

许多映射只能通过Fluent API获得.如果你在VS中跟随我们学习,强烈推荐您创建两个单独的解决方案。否则,当使用了Data Annotation中还想看看在Fluent API中同样的配置效果,你就不得不注释掉有关代码。然后当你使用另一个Data Annotation特性标记,你又不得不注释掉Fluent API代码.在注释与取消注释之间来回调整,万一出现错误就会导致抛出异常,要么是配置重复要么是配置丢失,可能会非常麻烦。

这就意味着在创建新类或添加新方法时需要进行许多必要的复制/粘贴操作.也意味着Data Annotations 只能应用于一个解决方案而Fluent 配置被强制用于另一个.

如果你遵循此建议,还有一个附加的建议.确保在两个解决方案使用不同的命名空间。如果其中一个解决方案使用了DataLayerForAnnotations命名空间,其数据库将为DataLayerForAnnotations.BrakeAwayContext。另一解决方案使用了DataLayerForFluent,命名空间,其数据库将为DataLayerForFluent.BrakeAwayContext。你会看到有两个独立的数据库,很容易理解哪个解决方案影响了哪个数据库。

DbContext首先在类中查找可以获取的信息。这时,context已经准备好解析模型,但对开发者来说有一个机会来中断context和执行附加配置的连接.这得益于DbContext.OnModelCreating方法,这是在模型创建前被上下文所调用的方法。方法是虚拟的,因此你可以覆写并加入你自已的逻辑代码.这就Fluent API进行配置的入口.

此方法的声明方式如下:

protected override void OnModelCreating(DbModelBuilder modelBuilder)

提供给OnModelCreating的参数DbModelBuilder是你需要添加配置的类。DbModelBuilder使用泛型和lambda表达式,所以编码是强类型的可以协助您进行配置的设置。首先要告诉DbModerBuilder对哪个类(实体)实施配置:

modelBuilder.Entity<Destination>() ;

你可以配置类映射到数据库的表名:

modelBuilder.Entity<Destination>().ToTable("a_table_name");

你也可配置类的属性.如果想要配置属性,应进一步演进:

modelBuilder.Entity<Destination>()
.Property(d => d.Description).HasMaxLength(500);

代码2-10重写了前面使用data annotations建立的配置。OnModelCrating是DbContext的一个方法,请确保它在BrakAwayContext类里。

Example 2-10. Configuring with the Fluent API

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Destination>()
.Property(d => d.Name).IsRequired();
modelBuilder.Entity<Destination>()
.Property(d => d.Description).HasMaxLength(500);
modelBuilder.Entity<Destination>()
.Property(d => d.Photo).HasColumnType("image");
modelBuilder.Entity<Lodging>()
.Property(l => l.Name).IsRequired().HasMaxLength(200);

}

如果你疑惑HasMinLength哪里去了,在Fluent配置方法里没有最小长度的配置,因为这不会对数据库的行产生影响.

除非要配合使用Data Annotations 和 Fluent API为了保持代码一致最好选择其一。为了让代码更流畅,我们已经移除了所有的Data Annotation标记.实际上Model项目也不需要对System.Component Model.DataAnnotations 或者EntityFramework程序集的引用.

再次运行代码,Code First将对比模型和数据库中的EdmMeta表,尽管我们修改了配置代码,最终结果还是一样的.同样的destination再次加入数据库中结束与匹配的记录.在图2-4你可以看到复制到的数据.

组织Fluent配置

如果你有很多配置需要执行,OnModelCreating 可能很快不堪重负(代码太多)。应该使用位于EntityTypeConfiguration的实体类来分组配置,然后在OnModelCretaing方法中告诉DbModelBuilde有些实体类r。DbModelBulider有一个Configruation属性可以来增加EntityTypeConfigurations(实体类型配置).

例2-111展示了对Destinaton类和Lodging类的分组情况:

Example 2-11. Organizing configs into separate EntityTypeConfiguration classes

using System.Data.Entity.ModelConfiguration;
using Model;
public class DestinationConfiguration :
EntityTypeConfiguration<Destination>
{
public DestinationConfiguration()
{
Property(d => d.Name).IsRequired();
Property(d =>
.Description).HasMaxLength(500);
Property(d => d.Photo).HasColumnType("image");
}
}
public class LodgingConfiguration :
EntityTypeConfiguration<Lodging>
{
public LodgingConfiguration()
{
Property(l => l.Name).IsRequired().HasMaxLength(200);
}
}

这些代码在OnModelCreating方法内部的时候,由DbModelBuilder开始,后面跟着Entity方法来确定哪个实体进行配置。在EntityConfiguration类中,是由继承于EntityTypeConfiguration类的类开始的,这里的实体类型已经指定。例如,modelBuilder.Entity<Destination>().Property这个语句是对属性进行设置,而调用的modelBuilder.Entity<Destination>()实际上是创建了一个EntityTypeConfiguration<Destination>对象并返回给你,然后在属性上配置。所以无论使用哪种方式,访问的是同一个API。

代码2-12,你会看到修改的OnModelCrating方法,来使用这些类.

Example 2-12. Adding the configuration classes in OnModelCreating

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new DestinationConfiguration());
modelBuilder.Configurations.Add(new LodgingConfiguration());

}

随着我们转向Fluent配置的例子,我们有时会将配置放在EntityTypeConfiguration类,有时放置在modelBulider中。这仅仅是为了让你继续看到这两种语法。但是,在最终产品中,很显然不能混用配置。你更希望有一个统一的方式,无论是将所有配置都写在OnModelCrating方法内部还是组织在EntityTypeConfiguration类中。你会看到有几个配置操作不是类型相关的,必须要直接在OnModelCreating方法中调用。

原文:http://www.cnblogs.com/qouoww/tag/Entity%20Framework/

时间: 2024-10-07 04:56:50

《转》Model First的相关文章

Data Model for Message Receiver

1. Physical Data Model 2. SQL Statements drop database MessageReceiver go /*==============================================================*/ /* Database: MessageReceiver */ /*==============================================================*/ create dat

springMVC:modelandview,model,controller,参数传递

转载:http://blog.csdn.net/wm5920/article/details/8173480 1.web.xml 配置: copy <> ></> ></> > >> ></> ></> > ></> </> <> ></> ></> </> 这样,所有的.htm的请求,都会被Dispatche

NHibernate框架与BLL+DAL+Model+Controller+UI 多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

原文://http://blog.csdn.net/wb09100310/article/details/47271555 1. 概述 搭建了Spring.NET+NHibernate的一个数据查询系统.之前没用过这两个框架,也算是先学现买,在做完设计之 后花了一周搭建成功了.其中,还加上了我的一些改进思想,把DAO和BLL之中相似且常用的增删改查通过泛型T抽象到了DAO和BLL的父类中,其DAO 和BLL子类只需继承父类就拥有了这些方法.和之前的一个数据库表(视图)对应一个实体,一个实体对应一

asp.net mvc 提交model 接收不了

[HttpPost]        //[ValidateInput(false)]        public ActionResult AddNews1(_54Young_News_Model.model.gou54contentall contentmodel, _54Young_News_Model.model.gou54user usermodel)        {} 发现用一些特殊符号提交不了, 然后以为说前端问题,把model去掉就可以了. 后面觉得是因为有特殊符号影响到转mod

Django操作model时,报错:AttributeError:’ProgrammingError’ object has no attribute ‘__traceback__’

原因:在Django项目下相应的应用下面的models.py配置的model(也就是class)没有创建成相应的表. 这是怎么回事呢? 首先,将models.py里面的model创建成对应的数据库表的执行命令(DOS命令)为:manage.py syncdb. 但是我自己的电脑上执行该命令时,显示.Unknown command:syncdb.执行,manage.py help后的确没有发现这个子命令.最后网上搜索发现这个命令已经在Django1.9里面取消了.并且stackoverflow里面

使用AutoMapper实现Dto和Model的自由转换(上)

在实际的软件开发项目中,我们的"业务逻辑"常常需要我们对同样的数据进行各种变换.例如,一个Web应用通过前端收集用户的输入成为Dto,然后将Dto转换成领域模型并持久化到数据库中.另一方面,当用户请求数据时,我们又需要做相反的工作:将从数据库中查询出来的领域模型以相反的方式转换成Dto再呈现给用户.有时候我们还会面临更多的数据使用需求,例如有多个数据使用的客户端,每个客户端都有自己对数据结构的不同需求,而这也需要我们进行更多的数据转换. 频繁的数据转换琐碎而又凌乱,很多时候我们不得不:

使用AutoMapper实现Dto和Model的自由转换(中)

在上一篇文章中我们构造出了完整的应用场景,包括我们的Model.Dto以及它们之间的转换规则.下面就可以卷起袖子,开始我们的AutoMapper之旅了. [二]以Convention方式实现零配置的对象映射 我们的AddressDto和Address结构完全一致,且字段名也完全相同.对于这样的类型转换,AutoMapper为我们提供了Convention,正如它的官网上所说的: 引用 AutoMapper uses a convention-based matching algorithm to

使用AutoMapper实现Dto和Model的自由转换(下)

书接上文.在上一篇文章中我们讨论了使用AutoMapper实现类型间1-1映射的两种方式--Convention和Configuration,知道了如何进行简单的OO Mapping.在这个系列的最后一篇文章我想基于我们的需求讨论一些中级别的话题,包括:如何实现类型体型之间的映射,以及如何为两个类型实现多个映射规则. [四]将一个类型映射为类型体系 先回顾一下我们的Dto和Model.我们有BookDto,我们有Author,每个Author有自己的ContactInfo.现在提一个问题:如何从

棋盘的多米诺覆盖:Dimer Lattice Model,Pfaff 多项式,Kasteleyn 定理

这次来介绍计数组合学里面一个经典的问题:Dimer Lattice Model.问题是这样的:一个有 64 个方格的国际象棋棋盘,有多少种不同的多米诺骨牌覆盖?这里的覆盖是指不重复不遗漏地盖住整个棋盘. 下图是一种可能的覆盖方式(图片来自 Wiki 百科): 这个问题的答案是 12988816,非常大的一个数字,绝对不是一个一个数出来的.1961 年德国物理学家 Kasteleyn 借助于线性代数中的一个结论首先解决了这个问题,我们接下来就介绍他的方法. ~~~~~~~~~~~~~~~~~~~~

RailsCast26 Hackers Love Mass Assignment rails中按params创建、更新model时存在的安全隐患

Mass assignment是rails中常用的将表单数据存储起来的一种方式.不幸的是,它的简洁性成了黑客攻击的目标.下面将解释为什么及如何解决. 上述表单为一个简单的注册表单.当用户填入name,点击提交时,一个新用户被创建.用户模型被如下定义: ruby create_table :users do |t| t.string :name t.boolean :admin, :default => false, :null => false end 当用户点击提交时,如下的action被执