EF 学习系列二 数据库表的创建和表关系配置(Fluent API、Data Annotations、约定)
上一篇写了《Entity Farmework领域建模方式 3种编程方式》,现在就Code First 继续学习
1、数据库表的创建
新建一个MVC的项目,在引用右击管理NuGet程序包,点击浏览搜索EF安装,我这里主要是EF6.0 以上的学习 所以都安装6.0 以上的版本

接下来在Model文件夹下面创建一个Customer类
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
public DateTime AddTime { get; set; }
}
在创建一个继承EF上下文的类XXDBContext,(个人习惯XX是我的名字拼音缩写)此上下文是数据库交互的一个中间桥梁,我们称之为会话,并且为为一个模型公开一个DbSet。默认情况下EF链接LocalDB本地数据库(需要安装LocalDB实例),我还是手动通过EF上下文派生类的构造函数来配置数据库链接。下面我注释的是数据库初始化策略。我这里就选择始终创建数据库,后面用到配置表关联与字段的配置。
public class WYDBContext:DbContext
{
public WYDBContext(string ConnectionName) : base(ConnectionName) { }
public WYDBContext():base("SqlConn")
{
//默认的初始化器。这种初始化器在第一次运行程序时会创建数据库,再次运行不会再创建新的数据库。但是如果我们改变了领域类,运行程序时会抛出一个异常
//Database.SetInitializer(new CreateDatabaseIfNotExists<WYDBContext>()); //如果领域类发生了改变,删除以前的数据库,然后重建一个新的。采用这种初始化器不用再担心领域类改变影响数据库架构的问题。
//Database.SetInitializer(new DropCreateDatabaseIfModelChanges<WYDBContext.cs>()); //每次运行程序都会删除以前的数据库,重建新的数据库。如果在开发过程中每次都想使用最新的数据库,那么可以采用这种初始化器。
Database.SetInitializer(new DropCreateDatabaseAlways<WYDBContext>()); //禁用数据库初始化策略
//Database.SetInitializer<WYDBContext>(null);
}
public DbSet<Customer> Customer { get; set; }
}
webconfig配置
<system.web>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1" />
</system.web> <!--数据库连接-->
<connectionStrings>
<!--数据库连接ef字符串-->
<add name="SqlConn" connectionString="Data Source=地址;Initial Catalog=数据库名;Persist Security Info=True;User ID=用户名;Password=密码;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
</connectionStrings>
现在如果直接启动项目数据库是不会被创建的,只有调用到才会创建,在Home控制器的Index中调用,启动就生成了数据库
public ActionResult Index()
{
using (var db =new WYDBContext())
{
db.Customer.ToList();
}
return View();
}

2、 三者约定之 Code First约定(三者优先级 Fluent API > Data Annotations > 约定)
上面可已看出表Customer自己生成了主键ID。所谓约定,类似于C#中的接口,它是一个规范或者规则。使用Code First基于类定义通过约定来配置概念模型并以此为规则,约定就是基本规则。
Code First根据模型中定义的ID(不区分大小写),或者是以类名加ID的属性推断这样的属性为ID,如果为int或者guid类型,那么主键映射成标识列(自增长)。
Model下面在创建一个订单Order类一个客户有多个订单一个订单只能属于某一个客户这样客户与订单的关系就是一对多
public class Order
{
public int ID { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Remark { get; set; }
public int CustomerID { get; set; }
/// <summary>
/// 订单对应的客户信息
/// </summary>
public virtual Customer Customer { get; set; }
} public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
public DateTime AddTime { get; set; }
/// <summary>
/// 客户对应的订单信息
/// </summary>
public virtual IList<Order> Order { get; set; }
}
数据库上下文WYDBContext加上 public DbSet<Order> Order { get; set; } 刚刚加的订单类,运行起来 如果数据库删除不了的 自己闪一下 (在navicat 里面使用会这样,我就换在SSMS里面用)

它也生成了表与表的对应关系,然而string类型的你会发现字段都是max这肯定不行。接下来看Data Annatations 配置
3、三者约定之 Data Annotations
Data Annotations我的理解就是在字段类名上面加特性注解来控制字段属性的 栗子如下 还是Order与Customer两张表 记得添加命名空间using System.ComponentModel.DataAnnotations;跟using System.ComponentModel.DataAnnotations.Schema;
public class Customer
{
/// <summary>
/// ID
/// </summary>
[Key]//标识次列为主键
[Column("Zj", Order = , TypeName = "int")]//列名Zj,数据库序号0,类型int
[Required()]//不允许为空
[Display(Name = "Zj")]//显示名称,这里大多都是中文 后面视图@Html.DisplayNameFor(item=> model.Name)用到 显示的
public int Zj { get; set; }
/// <summary>
/// 姓名
/// </summary>
[Column("NameWYY", TypeName = "nvarchar")]//我加了WYY看效果
[StringLength(, ErrorMessage = "{0}长度不能超过50个字符")]
[Display(Name = "姓名")]
public string Name { get; set; }
/// <summary>
/// 年龄
/// </summary> [Column("Age", TypeName = "int")]
[Display(Name = "年龄")]
public int? Age { get; set; }//加了?允许为null
/// <summary>
/// 邮箱
/// </summary>
[Column("Email", TypeName = "nvarchar")]
[StringLength(, ErrorMessage = "{0}长度不能超过50个字符")]
[Display(Name = "电子邮箱")]
public string Email { get; set; }
/// <summary>
/// 日期
/// </summary>
[Column("AddTime", TypeName = "datetime2")]//如果不定义datetime2添加DateTime.Now就会报错哦
[Display(Name = "添加日期")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]//日期格式化
public DateTime AddTime { get; set; }
/// <summary>
/// 客户对应的订单信息
/// </summary>
public virtual IList<Order> Order { get; set; }
} // [NotMapped]//表不映射到数据库
[Table("Tb_Order")]//表名
public class Order
{
/// <summary>
/// ID
/// </summary>
[Key]
[Column("ID", Order = , TypeName = "int")]
[Required()]
[Display(Name = "ID")]
public int ID { get; set; }
/// <summary>
/// 名称
/// </summary>
[Column("Name", TypeName = "nvarchar")]
[StringLength(, ErrorMessage = "{0}长度不能超过50个字符")]
[Display(Name = "名称")]
public string Name { get; set; }
/// <summary>
/// 价格
/// </summary>
[Column("Price")]
[Display(Name = "价格")]
public decimal? Price { get; set; }
/// <summary>
/// 备注
/// </summary>
[StringLength()]//长度约束
[Column("Remark", TypeName = "nvarchar")]//我加了WYY看效果
[Display(Name = "备注")]
public string Remark { get; set; }
/// <summary>
/// 客户ID
/// </summary>
[ForeignKey("Customer")]//外键
public int CustomerID { get; set; }
/// <summary>
/// 订单对应的客户信息
/// </summary>
[ForeignKey("CustomerID")]//外键
public virtual Customer Customer { get; set; } /// <summary>
/// 不映射字段
/// </summary>
[NotMapped]//不映射到数据库
public string XXX { get; set; }
}

4、三者约定之 Fluent API
这个就要在派生类重写OnModelCreating了 少一点 的表还可以在里面设置各个字段多了还是映射Map在模型表里面写,在OnModelCreatiing注册模型类就可以了;
public DbSet<Customer> Customer { get; set; }
public DbSet<Order> Order { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//TODO 配置映射
modelBuilder.Entity<Customer>().ToTable("CSTo");//数据库表名
modelBuilder.Entity<Customer>().HasKey(x => x.Zj);//主键
modelBuilder.Entity<Customer>().Property(x=>x.AddTime).HasColumnType("DATETIME2");//时间
modelBuilder.Entity<Customer>().Property(x=>x.Age).IsOptional();//为null
//HasColumnType("DATETIME2(7)")这种写是错的
modelBuilder.Entity<Customer>().Property(x => x.Name).IsRequired().HasColumnType("varchar").HasMaxLength();//不为空,类型,长度
//默认情况下不会生成复数的表 如Orders
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations.Add(new OrderMap());//注册
base.OnModelCreating(modelBuilder);
}
// [NotMapped]//表不映射到数据库
[Table("Tb_Order")]//表名
public class Order
{
///字段
}
public class OrderMap : EntityTypeConfiguration<Order>
{
public OrderMap()
{
//对应数据库表名
this.ToTable("ORd");
//一个订单必须对应有一个客户,客户一对多(订单) 用户表里面的 CustomerID
this.HasRequired(p => p.Customer).WithMany(p => p.Order).HasForeignKey(p => p.CustomerID);
this.HasKey(k => k.ID);//主键
this.Property(p => p.Name).HasColumnType("VARCHAR").HasMaxLength().IsRequired();//Name字段属性(varchar,长度50,不为null)
this.Property(p => p.Remark).HasColumnType("VARCHAR").HasMaxLength().IsOptional();//Remark(varchar,长度5000,null)
this.Property(p => p.Price).HasColumnName("pp");//列名
}
}

C#的数值类型对应数据库如下
●C#中的 int类型默认映射后对应数据库中的int类型。
● C#中的double类型默认映射后对应数据库中的float类型
●C#中的float类型默认映射后对应数据库中的real类型。
●C#中 的decimal类型默认映射后对应数据库中的decimal(18,2)类型
●C#中 的Int64类型默认映射后对应数据库中的bigint类型。
一般都是用Data Anntations 跟默认的约定好久没用记录一下 用到又来拿 Fluent API也是好久没复习了 哈哈 有时间在看看书
EF 学习系列二 数据库表的创建和表关系配置(Fluent API、Data Annotations、约定)的更多相关文章
- windows下mongodb基础玩法系列二CURD操作(创建、更新、读取和删除)
windows下mongodb基础玩法系列 windows下mongodb基础玩法系列一介绍与安装 windows下mongodb基础玩法系列二CURD操作(创建.更新.读取和删除) windows下 ...
- MyBatis学习系列二——增删改查
目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring 数据库的经典操作:增删改查. 在这一章我们主要说明一下简单的查询和增删改, ...
- scrapy爬虫学习系列二:scrapy简单爬虫样例学习
系列文章列表: scrapy爬虫学习系列一:scrapy爬虫环境的准备: http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_python_00 ...
- [转]ASP.NET MVC学习系列(二)-WebAPI请求 传参
[转]ASP.NET MVC学习系列(二)-WebAPI请求 传参 本文转自:http://www.cnblogs.com/babycool/p/3922738.html ASP.NET MVC学习系 ...
- RabbitMQ学习系列二-C#代码发送消息
RabbitMQ学习系列二:.net 环境下 C#代码使用 RabbitMQ 消息队列 http://www.80iter.com/blog/1437455520862503 上一篇已经讲了Rabbi ...
- 图机器学习(GML)&图神经网络(GNN)原理和代码实现(前置学习系列二)
项目链接:https://aistudio.baidu.com/aistudio/projectdetail/4990947?contributionType=1 欢迎fork欢迎三连!文章篇幅有限, ...
- [Unity3D插件]2dtoolkit系列二 动画精灵的创建以及背景图的无限滚动
经过昨天2dtoolkit系列教程一的推出,感觉对新手还有有一定的启发作用,引导学习使用unity 2dToolKit插件的使用过程,今天继续系列二——动画精灵的创建,以及背景图的无限循环滚动,在群里 ...
- .net reactor 学习系列(二)---.net reactor界面各功能说明
原文:.net reactor 学习系列(二)---.net reactor界面各功能说明 安装了.net reactor之后,可以在安装目录下找到帮助文档REACTOR_HELP.c ...
- Spring5.0源码学习系列之浅谈BeanFactory创建
Spring5.0源码学习系列之浅谈BeanFactory创建过程 系列文章目录 提示:Spring源码学习专栏链接 @ 目录 系列文章目录 博客前言介绍 一.获取BeanFactory主流程 二.r ...
随机推荐
- 字母间距letter-spacing
效果图: 字母间距CSS: h1 {letter-spacing:2px} h2 {letter-spacing:-3px}
- oracle函数 log(x,y)
[功能]返回以x为底的y的对数 [参数]x,y,数字型表达式, [条件]x,y都必须大于0 [返回]数字 [示例] select power(4,2),log(16,2),1/log(16,4) fr ...
- Libev源码分析09:select突破处理描述符个数的限制
众所周知,Linux下的多路复用函数select采用描述符集表示处理的描述符.描述符集的大小就是它所能处理的最大描述符限制.通常情况下该值为1024,等同于每个进程所能打开的描述符个数. 增大描述符集 ...
- Vue点击事件失效
在做项目时给button添加click事件,发现没反应,但另外写了一个button添加同样的事件,却能触发.原因是使用了better-scroll,默认它会阻止touch事件.所以在配置中需要加上cl ...
- Android教程 -04 启动其它Activity,静态工厂设计模式传递数据
视频建议采用超清模式观看, 欢迎点击订阅我的优酷 意图 Intent 一个应用程序肯定不只有一个界面,如何切换到其它界面,只时候就需要启动其它的Activity.启动Activity有多种方式.我在这 ...
- hdu 4063 Aircraft (Geometry + SP)
Problem - 4063 几何加简单最短路. 题意是给出若干圆的圆心以及半径,求出从给出的起点到终点的最短路径的长度,可以移动的区域是圆覆盖到的任意一个位置. 做法是这样的,对圆两两求交点,用这些 ...
- oracle 优化GROUP BY
提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉.下面两个查询返回相同结果但第二个明显就快了许多. 低效: SELECT JOB , AVG(SAL) FROM ...
- lodap问题集锦
1.分页打印时,同一行显示在不同页内 ,调整行分页粒度 LODOP.SET_PRINT_STYLEA(0, "TableRowThickNess", 40);
- hdu 3374 String Problem (字符串最小最大表示 + KMP求循环节)
Problem - 3374 KMP求循环节. http://www.cnblogs.com/wuyiqi/archive/2012/01/06/2314078.html 循环节推导的证明相当 ...
- css超出盒子隐藏
效果如图1-1. 效果图1-1 css代码: white-space: nowrap;overflow: hidden; text-overflow: ellipsis; display: inlin ...