一、EF框架三种开发模式(必考区分)
1. DB First 数据库优先(最常用)
先有数据库、数据表,VS根据数据库自动生成实体类、上下文。
特点:适合传统项目、已有数据库、快速开发、不用手写实体。
2. Code First 代码优先
先手写实体类、上下文,通过迁移命令自动生成/更新数据库表结构。
特点:适合新项目、敏捷开发、版本迭代、字段新增修改。
3. Model First 模型优先
拖拽模型设计器生成实体关系,再生成数据库,目前基本淘汰。
二、DBFirst 数据库优先(EF封装CRUD + 导航属性)
1. 核心概念:导航属性(必背)
导航属性:实体类中用于描述表与表外键关联的属性。
作用:无需手写联表SQL,直接通过对象点属性获取关联表数据。
示例:public AddressInfo AddressInfo { get; set; }
2. 全局上下文对象
// 全局数据库上下文
BankSystemEntities context = new BankSystemEntities();
3. 导航属性联表查询
private void button4_Click(object sender, EventArgs e)
{
// 1. 查询主表单个对象
UserInfo u1 = context.UserInfo.Find(1);
// 2. 通过导航属性直接获取外键关联的子表数据(无需Join)
foreach (var a in u1.AddressInfo.ToList())
{
MessageBox.Show(a.City);
}
}
4. EF 添加数据
private void button1_Click(object sender, EventArgs e)
{
// 1. 实例化实体
UserInfo u1 = new UserInfo()
{
Account = "123",
Password = "123",
CreateUserId = 1,
LastUpdateTime = DateTime.Now,
CreateTime = DateTime.Now,
Status = 1
};
// 2. 上下文临时添加
context.UserInfo.Add(u1);
// 3. 提交到数据库(核心)
int row = context.SaveChanges();
if (row > 0)
{
MessageBox.Show("添加成功");
BindView();
}
else
{
MessageBox.Show("添加失败");
}
}
5. EF 删除数据
private void button2_Click(object sender, EventArgs e)
{
if (dataGridView1.SelectedRows.Count > 0)
{
int id = Convert.ToInt32(dataGridView1.SelectedRows[0].Cells["UserId"].Value);
UserInfo u1 = context.UserInfo.Find(id);
// 删除方式一:Remove移除对象
context.UserInfo.Remove(u1);
// 删除方式二:修改实体状态为删除
// context.Entry(u1).State = System.Data.Entity.EntityState.Deleted;
int row = context.SaveChanges();
if (row > 0)
{
MessageBox.Show("删除成功");
BindView();
}
}
}
6. EF 修改数据
private void button3_Click(object sender, EventArgs e)
{
if (dataGridView1.SelectedRows.Count > 0)
{
int id = Convert.ToInt32(dataGridView1.SelectedRows[0].Cells["UserId"].Value);
UserInfo u1 = context.UserInfo.Single(m => m.UserId == id);
// 赋值更新
u1.Password = "888888";
u1.Account = "787777";
// 自动追踪属性变更,无需手动标记状态
int row = context.SaveChanges();
if (row > 0)
{
BindView();
}
}
}
7. 数据绑定方法
private void BindView()
{
dataGridView1.DataSource = context.UserInfo.ToList();
}
private void Form1_Load(object sender, EventArgs e)
{
BindView();
// 隐藏导航属性列(避免界面乱码)
if (dataGridView1.Columns["AddressInfo"] != null)
{
dataGridView1.Columns["AddressInfo"].Visible = false;
}
}
三、EF 执行原生SQL语句(参数化防注入)
适用场景:复杂SQL、存储过程、EF语法难以实现的查询
1. 原生SQL查询数据
private void BindView()
{
string sql = "select * from UserInfo";
// 执行查询SQL,返回实体集合
List<UserInfo> list = context.Database.SqlQuery<UserInfo>(sql).ToList();
dataGridView1.DataSource = list;
}
2. 原生SQL新增(参数化)
private void button1_Click(object sender, EventArgs e)
{
string sql = "insert into UserInfo(Account,Password,CreateUserId,CreateTime,LastUpdateTime,Status) " +
"VALUES(@Account,@Password,@CreateUserId,@CreateTime,@LastUpdateTime,@Status)";
// 防止SQL注入
SqlParameter[] paras = new SqlParameter[]
{
new SqlParameter("@Account","123456"),
new SqlParameter("@Password","123456"),
new SqlParameter("@CreateUserId",1),
new SqlParameter("@CreateTime",DateTime.Now),
new SqlParameter("@LastUpdateTime",DateTime.Now),
new SqlParameter("@Status",0)
};
int row = context.Database.ExecuteSqlCommand(sql, paras);
if (row > 0)
{
MessageBox.Show("插入成功");
BindView();
}
}
3. 原生SQL修改、删除
// 修改
private void button2_Click(object sender, EventArgs e)
{
string sql = "update UserInfo set Account = @Account,Password =@Password where UserId=@UserId";
SqlParameter[] paras = new SqlParameter[]
{
new SqlParameter("@Account","123456"),
new SqlParameter("@Password","123456888"),
new SqlParameter("@UserId",5006),
};
int row = context.Database.ExecuteSqlCommand(sql, paras);
}
// 删除
private void button3_Click(object sender, EventArgs e)
{
string sql = "delete from UserInfo where UserId = @UserId";
SqlParameter[] paras = new SqlParameter[]
{
new SqlParameter("@UserId",5005),
};
int row = context.Database.ExecuteSqlCommand(sql, paras);
}
4. 原生SQL多表查询替代导航属性
private void button4_Click(object sender, EventArgs e)
{
// 1. 查询主表
string sql = "select * from UserInfo where UserId=@UserId";
SqlParameter para = new SqlParameter("@UserId", 1);
UserInfo info = context.Database.SqlQuery<UserInfo>(sql, para).FirstOrDefault();
// 2. 根据主表ID查询子表
string sql1 = "select * from AddressInfo where CreateUserId=@a";
SqlParameter para1 = new SqlParameter("@a", info.UserId);
List<AddressInfo> list = context.Database.SqlQuery<AddressInfo>(sql1, para1).ToList();
foreach (var item in list)
{
MessageBox.Show(item.City);
}
}
四、EF CodeFirst 代码优先完整流程
1. 使用步骤(必背考试步骤)
NuGet 安装EF:Install-Package EntityFramework -Version 6.5.2
配置数据库连接字符串
手写实体类
创建上下文类,继承 DbContext
执行迁移命令生成/更新数据库
2. 迁移命令(必考)
Enable-Migrations // 首次开启迁移
Add-Migration init // 添加迁移记录(init=初始化)
Update-Database // 更新到数据库
// 新增字段迭代
Add-Migration AddNewColumn
Update-Database
3. CodeFirst 新增数据示例
namespace _02ef代码优先
{
public partial class Form1 : Form
{
UserInfoModel u1 = new UserInfoModel();
public void BindView()
{
dataGridView1.DataSource = u1.UserInfos.ToList();
}
private void button1_Click(object sender, EventArgs e)
{
UserInfo u2 = new UserInfo()
{
Account = "123456",
Password = "Password",
Status = 1,
Status1 = 0
};
u1.UserInfos.Add(u2);
int row = u1.SaveChanges();
if (row > 0)
{
MessageBox.Show("添加成功");
BindView();
}
}
}
}
五、LINQ 全套基础语法(查询语法 + 方法语法)
1. 两种查询模式
-
查询语法(from):可读性高、类似SQL
-
方法语法(Lambda):简洁、企业常用
2. 查询语法基础
int[] ints = new int[] { 1, 2, 3, 4, 5, 6 };
// 条件、排序、投影
IEnumerable<string> query = from s in ints
where s > 1 && s < 4
orderby s descending
select s + "分";
foreach (var s in query)
{
MessageBox.Show(s);
}
3. 字符串模糊查询
string[] names = { "xibanya", "agenting", "faguo" };
var query1 = from s in names
where s.StartsWith("a")
select s;
4. 嵌套集合查询
Student[] students = new Student[]
{
new Student() { Id =1,Name="罗志祥",Favobrite = new string[]{"聊天","跳舞","rap"} },
new Student() { Id =2,Name="吴亦凡",Favobrite = new string[]{"唱歌","跳舞","rap"} },
new Student() { Id =3,Name="蔡徐坤",Favobrite = new string[]{"唱歌","跳舞","rap","打篮球"} },
};
// 嵌套from查询子集合
var query3 = from s in students
where s.Name == "蔡徐坤"
from s2 in s.Favobrite
where s2.EndsWith("球")
select s2;
5. Lambda 方法语法(Where/OrderBy/Select)
int[] ints = { 1, 2, 3, 4 };
// 筛选 + 排序 + 投影
var query1 = ints.Where(v => v > 2)
.OrderByDescending(v => v)
.Select(v => v * 2);
六、LINQ + EF 分页 + 多条件筛选(大题终极模板)
namespace _04linq和代码优先示例
{
public partial class Form1 : Form
{
public MyEntities my = new MyEntities();
public int pageIndex = 1;
public int pageSize = 2;
// 绑定数据(筛选 + 分页)
private void BindView()
{
using (MyEntities my = new MyEntities())
{
IQueryable<StudentInfo> query = getFilterQuery(my);
// 分页核心代码
var list = query.Skip((pageIndex – 1) * pageSize)
.Take(pageSize)
.ToList();
dataGridView1.DataSource = list;
}
}
// 通用多条件筛选
public IQueryable<StudentInfo> getFilterQuery(MyEntities m)
{
IQueryable<StudentInfo> query = m.StudentInfos;
// 模糊查询
if (!string.IsNullOrEmpty(textBox1.Text))
{
query = query.Where(v => v.Name.Contains(textBox1.Text));
}
// 下拉框状态筛选
if (comboBox1.SelectedIndex > 0)
{
int a = Convert.ToInt32(comboBox1.Text);
query = query.Where(v => v.Status == a);
}
// 排序
query = query.OrderByDescending(v => v.Id);
return query;
}
// 上一页、下一页
private void button1_Click(object sender, EventArgs e) { pageIndex++; BindView(); }
private void button3_Click(object sender, EventArgs e)
{
if (pageIndex > 1) pageIndex–;
BindView();
}
}
}
七、期末必背核心考点总结
导航属性:替代联表SQL,快速获取外键关联数据,DBFirst自动生成
EF两种操作方式:1. EF语法CRUD 2. 原生SQL参数化CRUD(防注入)
CodeFirst三步:安装EF、写实体+上下文、迁移命令生成数据库
LINQ两种写法:查询语法(from)、Lambda方法语法
分页核心函数:Skip()跳过条数、Take()读取条数
IQueryable/IEnumerable区别:IQueryable延迟查询、性能高;IEnumerable本地内存筛选




