Code First模式
代码优先(编写代码来自动创建模型和数据库)
使用类创建模型
- 创建ASP.NET MVC应用程序,并选择“基本”模板
- 在Models文件夹上右键选择新建类,并命名为ks类
public class ks
{
public int id { get; set; }
public string Name { get; set; }
public string PassWord { get; set; }
public virtual ICollection<sl> sl { get; set; }
}
- 继续新建类并命名为sl
public class sl
{
public int id { get; set; }
public string Phone { get; set; }
public virtual ks ks { get; set; }
}
- 创建数据上下文类,表示数据库的一个会话,以便查询和绑定对象
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity; //记得引用
namespace Demo4.Models
{
public class mlgm : DbContext //引用DbContext父类
{
public DbSet<ks> ks { get; set; }
public DbSet<sl> sl { get; set; }
}
}
PS:带virtual的属性,称为“导航属性”。表示启用EF框架的延迟加载功能。延迟加载意味着,尝试访问这些属性内容时,将自动从数据库加载。
生成数据库:
- 打开Web.config,查找数据库连接字符串“DefaultConnection”,将其修改为:
<add name="mlgm" providerName="System.Data.SqlClient" connectionString="Data Source=.;Initial Catalog=sy;Integrated Security=SSPI;" />
PS:name属性对应数据库上下文类类名,connectionString中Initial Catalog对应数据库名,Integrated Security=SSPI表示启用Window登录验证
2. 新建控制器和视图,在控制器中的Index方法中,编写以下代码
public ActionResult Index()
{
using (mlgm m = new mlgm())
{
ks k = new ks();
k.Name = "美丽副矛";
k.PassWord = "刷卡单";
m.ks.Add(k);
m.SaveChanges();
}
return View();
}
- 启动程序,打开SQLServer,就可以看到自动创建的sy数据库了其中ks表中还有一条新增数据
模型的默认约定
- 表和字段名的约定
Code First约定表名使用EF框架的复数化服务,即使用英语语法的类名复数形式来命名表名。
关闭代码如下:
数据库上下文类中引用(using System.Data.Entity.ModelConfiguration.Conventions;)并输入
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
默认情况下,每个表都使用dbo框架创建。
实体类属性映射的列与类中字段的名称一致命名。
-
关于主键的约定
Code First默认约定将命名为id或“类名+id”的属性视为表的主键。
如果这些属性还是整型类型,Code First会自动将他们配置为数据库的标识字段
PS:SQLserver2012不区分大小写,所以id或者ID什么的都一样 -
字符串属性的约定
默认数据类型nvarchar(max),同时允许空值 -
一对多关系的约定
sl类中有一个ks类型的属性,ks类中有一个List属性。Code First将此视为一对多关系,自动给sl生成一个外键约束的属性。
更新数据库
数据上下文类中添加类的无参构造函数
//手动设置数据库初始化(先删再加)
public mlgm()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<mlgm>());
}
主从表查询
- 延迟加载
只在需要的时候加载数据,当对象使用时,再去数据库中加载。当实体对象读取数据时,关联的数据并不会被获取。只有访问关联属性时,被导航属性关联的数据才会被自动读取。这可能导致多次查询被发送到数据库,一次是读取实体本身,对于关联的每个实体也需要分别读取。 - 贪婪加载
一次性组织好数据,并加载到内存。当实体加载时,向关联的数据也一同被加载。典型运用于一次连接查询后返回所有需要的相关数据的情况。 - 显示加载
这种方式类似于延迟加载,除非需要在代码中显示获取数据。在访问导航属性时,不会出现自动加载。手动加载关联的数据,通过访问对象状态管理器来获取实体,调用Collection.Load方法获取集合,或调用持有单个实体的属性的Reference.Load方法
优劣:
贪婪加载:
1、减少数据访问的延迟,在一次数据库的访问中返回所有的数据。
2、一次性读取所有相关的数据,可能导致部分数据实际无需用到,从而导致读取数据的速度变慢,效率变低
延迟加载:
1、只在需要读取关联数据的时候才进行加载
2、可能因为数据访问的延迟而降低性能,因为循环中,每一条数据都会访问一次数据库,导致数据库的压力加大
EF默认支持延迟加载,有两种方法可以关闭延迟加载: 1. 对于特定的导航属性,在定义属性时取消virtual
2. 对于所有的导航属性在数据上下文类的构造函数中设置LazyLoadingEnabled为false
Configuration.LazyLoadingEnabled = false;
代码块:
m是数据上下文类对象,ks是主表,sl是从表
//延迟加载(只加载主表数据)
var user = from u in m.ks where u.ksID == 1 select u;
//贪婪加载(可以和linq查询共用)(在一次数据库的访问中返回所有的数据)(加载主从表数据)
var user = from u in m.ks.Include("sl") where u.ksID == 1 select u;
//遍历
foreach (ks l in user)
{
foreach (sl o in l.sl) //EF查询导航属性的时候,只要查询到内存没有相应的数据,每次会再度向去查询一下数据库
{
}
}