实体框架 (EF) 入门 => 三、CodeFirst 支持的完整特性列表
设置主键。如果为int类型,将自动设置为自增长列。
系统默认以Id或类名+Id作为主键。
StringLengthAttribute可设置最大最小长度以及验证提示信息等。最大长度会映射到数据库。
MaxLengthAttribute最大长度。会映射的数据库。
ConcurrencyCheckAttribute修改或删除时,将带此属性的列的原有值与主键一起传送到数据库,如果传递的值与数据库中不一致,则修改或删除失败。用于并发检查。
RequiredAttribute必填字段。将映射到数据库,使字段属性为 not null。客户段作必填项验证。
TimestampAttribute用于并发检查,一个实体类中只能有一个标记为此属性。
[Timestamp] public Byte[] TimeStamp { get; set; }这样,Code First 将在数据库表中创建一个不可为空的 Timestamp 列。
指定列名
[Column(“BlogDescription", TypeName="ntext")]
public String Description {get;set;}
TableAttribute指定表名
[Table("InternalBlogs")]
public class Blog
InversePropertyAttribute两个类之间存在多个关系时,将使用 InverseProperty。
ForeignKeyAttribute用于外键名称与主键不一致的情况。
DatabaseGeneratedAttributeIdentity 自增长列,一般主键会自动设置此属性,非主键才需要设置。
None 用于不将主键设置为自增长列。
Computed 不让实体框架尝试更新这些列,一般用于使用默认值。
[DatabaseGenerated(DatabaseGenerationOption.Computed)]
不能添加[Required],验证通不过。也不必添加[Required],数据库中自动设置为 not null。bool => 0 (false)
int => 0
float => 0
decimal => 0
datetime => 1900-01-01 00:00:00
byte => 0 在数据库中为 tinyint (取值范围0-255)
short=> 0 在数据库中为 smallyint
如果设置了
[DatabaseGenerated(DatabaseGenerationOption.Computed)] ,再取消,数据库中也不会修改
除了string 外,基本都允许有默认值数值类型也没有必要在数据库中添加默认值,值类型在初始化时,自动会赋予默认值并保存到数据库中。
datetime 或 string 如果想使用默认值,可以在构造函数中进行初始化。
不映射到数据库,一般用于将映射到数据库的字段通过计算获取只读值。
通过实体框架 Code First,可以使用您自己的域类表示 EF 执行查询、更改跟踪和更新函数所依赖的模型。Code First 利用称为“约定先于配置”的编程模式。这就是说,Code First 将假定您的类遵从 EF 所使用的约定。在这种情况下,EF 将能够找出自己工作所需的详细信息。但是,如果您的类不遵守这些约定,则可以向类中添加配置,以向 EF 提供它需要的信息。
Code First 为您提供了两种方法来向类中添加这些配置。一种方法是使用名为 DataAnnotations 的简单特性,另一种方法是使用 Code First 的 Fluent API,该 API 向您提供了在代码中以命令方式描述配置的方法。
本文重点介绍如何使用 DataAnnotations(在 System.ComponentModel.DataAnnotations 命名空间中)对类进行配置,着重讲述常用的配置。很多 .NET 应用程序(如 ASP.NET MVC)都能够理解 DataAnnotations,它允许这些应用程序对客户端验证使用相同的注释。
我将通过 Blog 和 Post 这两个简单的类来说明 Code First DataAnnotations。
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string BloggerName { get; set;}
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime DateCreated { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public ICollection<Comment> Comments { get; set; }
}
Blog 和 Post 类本身就遵守 Code First 约定,无需调整即可让 EF 与之共同使用。但您也可以使用注释向 EF 提供有关类以及类所映射到的数据库的更多信息。
键
实体框架依赖于每个具有键值的实体,它使用键值来跟踪实体。Code First 依赖的一个约定是它在每一个 Code First 类中以何种方式表示哪一个属性是键。该约定是查找名为“Id”或类名与“Id”组合在一起(如“BlogId”)的属性。该属性将映射到数据库中的主键列。
Blog 和 Post 类都遵守此约定。但如果它们不遵守呢?如果 Blog 使用名称 PrimaryTrackingKey,甚至使用 foo 呢?如果 Code First 找不到符合此约定的属性,它将引发异常,因为实体框架要求必须要有一个键属性。您可以使用键注释来指定要将哪一个属性用作 EntityKey。
public class Blog
{
[Key]
public int PrimaryTrackingKey { get; set; }
public string Title { get; set; }
public string BloggerName { get; set;}
public virtual ICollection<Post> Posts { get; set; }
}
如果您在使用 Code First 的数据库生成功能,则 Blog 表将具有名为 PrimaryTrackingKey 的主键列,该列默认情况下还定义为 Identity。
.png)
必需
Required 注释告诉 EF 某一个特定属性是必需的。
在 Title 属性中添加 Required 将强制 EF(和 MVC)确保该属性中包含数据。
[Required]
public string Title { get; set; }
MVC 应用程序无需添加其他代码或更改标记,就能执行客户端验证,甚至还能使用属性和注释名称动态生成消息。
Required 特性还将使被映射的属性不可为空来影响生成的数据库。请注意,Title 字段已经更改为“not null”。
.png)
MaxLength 和 MinLength
使用 MaxLength 和 MinLength 特性,您可以就像对 Required 那样指定其他属性验证。
下面是具有长度要求的 BloggerName。该示例也说明如何组合特性。
[MaxLength(10),MinLength(5)]
public string BloggerName { get; set; }
MaxLength 注释将通过把属性长度设置为 10 来影响数据库。
.png)
MVC 客户端注释和 EF 4.1 服务器端注释都要执行此验证,也会动态生成错误消息:“字段 BloggerName 必须是最大长度为 10 的字符串或数组类型。”该消息有一点长。很多注释都允许您使用 ErrorMessage 特性来指定错误消息。
[MaxLength(10, ErrorMessage="BloggerName 必须在 10 个字符以下"),MinLength(5)]
public string BloggerName { get; set; }
您也可以在 Required 注释中指定 ErrorMessage。
.png)
NotMapped
Code First 约定指示具有受支持数据类型的每个属性都要在数据库中有表示。但在您的应用程序中并不总是如此。例如,您可以在 Blog 类中使用一个属性来基于 Title 和 BloggerName 字段创建代码。该属性可以动态创建,无需存储。您可以使用 NotMapped 注释来标记不映射到数据库的所有属性,如下面的 BlogCode 属性。
[NotMapped]
public string BlogCode
{
get
{
return Title.Substring(0, 1) + ":" + BloggerName.Substring(0, 1);
}
}
ComplexType
跨一组类描述域实体,然后将这些类分层以描述一个完整实体的情况并不少见。例如,您可以向模型中添加一个名为 BlogDetails 的类。
public class BlogDetails
{
public DateTime?DateCreated { get; set; }
[MaxLength(250)]
public string Description { get; set; }
}
请注意,BlogDetails 没有任何键属性类型。在域驱动的设计中,BlogDetails 称为值对象。实体框架将值对象称为复杂类型。复杂类型不能自行跟踪。
但是 BlogDetails 作为 Blog 类中的一个属性,将作为 Blog 对象的一部分被跟踪。为了让 Code First 认识到这一点,您必须将 BlogDetails 类标记为 ComplexType。
[ComplexType]
public class BlogDetails
{
public DateTime?DateCreated { get; set; }
[MaxLength(250)]
public string Description { get; set; }
}
现在,您可以在 Blog 类中添加一个属性来表示该博客的 BlogDetails。
public BlogDetails BlogDetail { get; set; }
在数据库中,Blog 表将包含该博客的所有属性,包括在其 BlogDetail 属性中所含的属性。默认情况下,每个属性都将添加复杂类型名称前缀 BlogDetail。
.png)
另外,有趣的是,虽然 DateCreated 属性在类中定义为不可为空的 DateTime,但相关数据库字段是可为空的。如果想影响数据库架构,则必须使用 Required 注释。
ConcurrencyCheck
ConcurrencyCheck 注释可用于标记要在用户编辑或删除实体时用于在数据库中进行并发检查的一个或多个属性。如果之前使用 EF 设计器,则这等同于将属性的 ConcurrencyMode 设置为 Fixed。
现在让我们将 ConcurrencyCheck 添加到 BloggerName 属性,看看它如何工作。
[ConcurrencyCheck, MaxLength(10, ErrorMessage="BloggerName must be 10 characters or less"),MinLength(5)]
public string BloggerName { get; set; }
调用 SaveChanges 时,因为 BloggerName 字段上具有 ConcurrencyCheck 注释,所以在更新中将使用该属性的初始值。该命令将尝试通过同时依据键值和 BloggerName 的初始值进行筛选来查找正确的行。下面是发送到数据库的 UPDATE 命令的关键部分,在其中您可以看到该命令将更新 PrimaryTrackingKey 为 1 且 BloggerName 为“Julie”(这是从数据库中检索到该博客时的初始值)的行。
where (([PrimaryTrackingKey] = @4) and ([BloggerName] = @5))
@4=1,@5=N'Julie'
如果在此期间有人更改了该博客的博主姓名,则此更新将失败,并引发 DbUpdateConcurrencyException 并且需要处理该异常。
TimeStamp
使用 rowversion 或 timestamp 字段来进行并发检查更为常见。但是比起使用 ConcurrencyCheck 注释,只要属性类型为字节数组,则不如使用更为具体的 TimeStamp 注释。Code First 将 Timestamp 属性与 ConcurrencyCheck 属性同等对待,但它还将确保 Code First 生成的数据库字段是不可为空的。在一个指定类中,只能有一个 timestamp 属性。
将以下属性添加到 Blog 类:
[Timestamp]
public Byte[] TimeStamp { get; set; }
这样,Code First 将在数据库表中创建一个不可为空的 Timestamp 列。
.png)
表和列
如果您让 Code First 创建数据库,则可能希望更改它创建的表和列的名称。也可以将 Code First 用于现有数据库。但是域中的类和属性的名称并不总是与数据库中表和列的名称相匹配。
我的类名为 Blog,按照约定,Code First 将假定此类映射到名为 Blogs 的表。如果不是这样,您可以用 Table 特性指定该表的名称。举例来说,下面的注释指定表名称为 InternalBlogs。
[Table("InternalBlogs")]
public class Blog
Column 注释更适于用来指定被映射列的特性。您可以规定名称、数据类型甚至列出现在表中的顺序。下面是 Column 特性的示例。
[Column(“BlogDescription", TypeName="ntext")]
public String Description {get;set;}
不要将列的 TypeName 特性与 DataType DataAnnotation 相混淆。DataType 是一个用于 UI 的注释,Code First 会将它忽略。
下面是重新生成后的表。表名称已更改为 InternalBlogs,复杂类型的 Description 列现在是 BlogDescription。因为该名称在注释中指定,Code First 不会使用以复杂类型名称作为列名开头的约定。
.png)
DatabaseGenerated
一个重要的数据库功能是可以使用计算属性。如果您将 Code First 类映射到包含计算列的表,则您可能不想让实体框架尝试更新这些列。但是在插入或更新数据后,您的确需要 EF 从数据库中返回这些值。您可以使用 DatabaseGenerated 注释与 Computed 枚举一起在您的类中标注这些属性。其他枚举为 None 和 Identity。
[DatabaseGenerated(DatabaseGenerationOption.Computed)]
public DateTime DateCreated { get; set; }
当 Code First 生成数据库时,您可以对 byte 或 timestamp 列使用生成的数据库,否则您只应该在指向现有数据库时使用,因为 Code First 将不能确定计算列的公式。
您阅读过以上内容,知道默认情况下,整数键属性将成为数据库中的标识键。这与将 DatabaseGenerated 设置为 DatabaseGenerationOption.Identity 是一样的。如果不希望它成为标识键,则可以将该值设置为 DatabaseGenerationOption.None。
[DatabaseGenerated(DatabaseGenerationOption.Computed)]
不能添加[Required],验证通不过。也不必添加[Required],数据库中自动设置为 not null。
bool => 0 (false)
int => 0
float => 0
decimal => 0
datetime => 1900-01-01 00:00:00
byte => 0 在数据库中为 tinyint (取值范围0-255)
short=> 0 在数据库中为 smallyint
如果设置了 [DatabaseGenerated(DatabaseGenerationOption.Computed)] ,再取消,数据库中也不会修改
除了string 外,基本都允许有默认值
关系特性:InverseProperty 和 ForeignKey
注意:此页面提供有关使用数据注释在 Code First 模型中设置关系的信息。有关 EF 中的关系的一般信息和如何使用关系来访问和操作数据,请参阅 关系和导航属性。
Code First 约定将在您的模型中处理最常用的关系,但是在某些情况下它需要帮助。
在 Blog 类中更改键属性的名称造成它与 Post 的关系出现问题。
生成数据库时,Code First 会在 Post 类中看到 BlogId 属性并识别出该属性,按照约定,它与类名加“Id”匹配,并作为 Blog 类的外键。但是在此 Blog 类中没有 BlogId 属性。解决方法是,在 Post 中创建一个导航属性,并使用 Foreign DataAnnotation 来帮助 Code First 了解如何在两个类之间创建关系(那就是使用 Post.BlogId 属性)以及如何在数据库中指定约束。
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime DateCreated { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
[ForeignKey("BlogId")]
public Blog Blog { get; set; }
public ICollection<Comment> Comments { get; set; }
}
数据库中的约束显示 InternalBlogs.PrimaryTrackingKey 与 Posts.BlogId 之间的关系。
.png)
类之间存在多个关系时,将使用 InverseProperty。
在 Post 类中,您可能需要跟踪是谁撰写了博客文章以及谁编辑了它。下面是 Post 类的两个新的导航属性。
public Person CreatedBy { get; set; }
public Person UpdatedBy { get; set; }
您还需要在这些属性引用的 Person 类中添加内容。Person 类具有返回到 Post 的导航属性,一个属性指向该用户撰写的所有文章,一个属性指向该用户更新的所有文章。
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public List<Post> PostsWritten { get; set; }
public List<Post> PostsUpdated { get; set; }
}
Code First 不能自行使这两个类中的属性匹配。Posts 的数据库表应该有一个表示 CreatedBy 人员的外键,有一个表示 UpdatedBy 人员的外键,但是 Code First 将创建四个外键属性:Person_Id、Person_Id1、CreatedBy_Id 和 UpdatedBy_Id。
.png)
要解决这些问题,您可以使用 InverseProperty 注释来指定这些属性的匹配。
[InverseProperty("CreatedBy")]
public List<Post> PostsWritten { get; set; }
[InverseProperty("UpdatedBy")]
public List<Post> PostsUpdated { get; set; }
因为 Person 中的 PostsWritten 属性知道这指的是 Post 类型,所以它将与 Post.CreatedBy 建立关系。同样,PostsUpdated 也将与 Post.UpdatedBy 建立关系。Code First 不会创建额外的外键。
.png)
表内主外键


实体框架 (EF) 入门 => 三、CodeFirst 支持的完整特性列表的更多相关文章
- 实体框架 (EF) 入门 => 一、我该用哪个工作流?
入门的参考资料:http://msdn.microsoft.com/zh-cn/data/ee712907 本篇的参考资料:http://msdn.microsoft.com/zh-cn/data/j ...
- 实体框架 (EF) 入门 => 四、CodeFirst 枚举支持
当使用 Code First 开发时,通常是从编写用来定义概念(域)模型的 .NET Framework 类开始. 插入记录没有为 Budget 赋值. 数值类型默认值为0,数据库中都为not nul ...
- 实体框架 (EF) 入门 => 六、性能注意事项
这个还真是复杂,看了看微软的文档,有些根本就看不懂,有些能看懂,但对我这种菜鸟也不会去用. 无从下手啊,前面放了几个链接,挨个试试吧. 一.显式打开连接 这个我测试过,有些时候,需要我们显示打开连接, ...
- 实体框架 (EF) 入门 => 二、在全新的数据库中使用 Code First
学习资料:http://msdn.microsoft.com/zh-cn/data/jj193542 视频建立的控制台应用程序,我在这里使用MVC. 一.非常有磁性的,非常优雅 很喜欢看这个人的视频, ...
- 实体框架 (EF) 入门 => 五、连接和模型
public class BloggingContext : DbContext { public BloggingContext() : base("name=Blo ...
- .NET实体框架EF之CodeFirst
ADO.NET Entity Framework 以 Entity Data Model (EDM) 为主,将数据逻辑层切分为三块,分别为 Conceptual Schema, Mapping Sch ...
- Oracle 免费的数据库--Database 快捷版 11g 安装使用与"SOD框架"对Oracle的CodeFirst支持
一.Oracle XE 数据库与连接工具安装使用 Oracle数据库历来以价格昂贵出名,当然贵有贵的道理,成为一个Oracle DBA也是令人羡慕的事情,如果程序员熟悉Oracle使用也有机会接触到大 ...
- Entity Framework(实体框架 EF)
什么是Entity Framework呢(下面简称EF)? EF(实体框架)是ADO.NET中的一组支持开发面向数据的软件应用程序的技术,是微软的一个ORM框架.ORM(对象关系映射框架):指的是面向 ...
- MyBatis框架之入门(三)
使用原始dao层进行开发 UserMapper层接口 public interface UserMapper { /** * 通过id查询用户 * @param id * @return */ Use ...
随机推荐
- Maven3路程(五)用Maven创建Hibernate项目
本文将用Maven3.Hibernate3.6.Oracle10g整合,作为例子. 环境清单: 1.Maven3.0.5 2.Hibernate3.6.5 Final 3.JDK1.7.0.11 4. ...
- innodb锁之间的兼容性判断
检查锁与锁之间的兼容性 路径:/mysql-5.5.43/storage/innobase/lock/lock0lock.c 实现:见锁的强度比较 row 可理解为 lock 的锁模式 colum ...
- 二维线性表 list实现
class Coordinate{ private int x; private int y; } List<Coordinate> list=new ArrayList<Coord ...
- Qt之自定义搜索框
简述 关于搜索框,大家都经常接触.例如:浏览器搜索.Windows资源管理器搜索等. 当然,这些对于Qt实现来说毫无压力,只要思路清晰,分分钟搞定. 方案一:调用QLineEdit现有接口 void ...
- UVa 12174 (滑动窗口) Shuffle
首先预处理一下以每个数为结尾的前s个数是否能构成一个1~s的排列. 可以用cnt数组来记录每个数出现的次数和用一个变量记录一共有多少个不同的数出现. 然后枚举每种可能的情况,也就是枚举第一首歌会出现的 ...
- 一招解决OpenERP8.0安装旧版模块报错
有喜欢尝鲜的网友开始玩8.0了,可是版本还没发布,社区的很多特别好的模块还没有升级到8,所以经常碰到模块无法安装的问题. No module name osv 网友提出将模块的 from osv im ...
- 今天发现猎豹浏览器的一个大坑 Request.IsAuthenticated 一直为 false;另外附加原因以及临时的解决方法
今天掉到了一个大坑里面,爬了1个多小时才发现不是代码的问题,居然是浏览器的问题… 下面是问题的发生过程 单点登陆 有2个站点 http://a.abc.com http://b.abc.com ...
- 01.C语言关于结构体的学习笔记
我对于学习的C语言的结构体做一个小的学习总结,总结如下: 结构体:structure 结构体是一种用户自己建立的数据类型,由不同类型数据组成的组合型的数据结构.在其他高级语言中称为记录(record) ...
- acdream 1681 跳远女王(BFS,暴力)
Problem Description 娜娜觉得钢琴很无趣了,就抛弃了钢琴,继续往前走,前面是一片湖,娜娜想到湖的对岸,可惜娜娜找了好久都没找到小桥和小船,娜娜也发现自己不是神仙,不能像八仙过海一样. ...
- UVa572 - Oil Deposits
解题思路:好久没写搜索了,练练手,陶冶情操.不多说,直接贴代码: #include<cstdio> #include<cstring> #include<algorith ...

