MVC概述
MVC基本原理
- 模型Model
用于封装与应用业务逻辑相关的数据以及用于控制访问和修改这些数据的业务规则。
- 控制器Controller
处理用户交互、与模型协作,并选择一个视图作为用户界面来显示。
-
视图View:显示结果的用户界面
MVC模式优点
- Controller与View完全分离,有利于前台与后台分工合作。
- 一个Model可建立多个视图,满足用户不同需求。
- Model独立于视图,可移植到新的平台,代码重用高,易于维护。
- 表现层的性能可以优化到极致。
- 容易对界面逻辑进行单元测试。
- 非常强大的URL映射组件,非常干净的URL来建造应用。
- 有利于软件工程化管理。
MVC项目架构
主要文件夹:
- App_Data:存放私有数据,如数据库文件。
- App_Start:存放项目的核心配置,如路由配置、绑定配置
- Content:存放CSS、图像等内容。
- Controllers:存放Controller类,处理URL请求。
- Models:存放业务实体类数据模型。
- Scripts:存放JavaScript类库文件和其他.js文件。
- Views:存放视图文件,按控制器分组,如Views/Home。
- Views/Shared:存放共享的布局或视图
根目录下2个重要文件:
- Global.asax:提供全局可用代码。
- Web.config:应用的系统配置文件。
HTML
view代码
控制器代码
public class TestHtmlController : Controller
{
public ActionResult Login()
{
return View();
}
}
三种方法接收数据
1.如果前一页面使用 method="get" 提交数据
Login页面欢迎你
输入的用户名: @Request.QueryString["username"]
输入的密码: @Request.QueryString["psd"]
2.如果前一页面使用method="post" 提交数据
Login页面欢迎你
输入的用户名: @Request.Form["username"]
输入的密码: @Request.Form["psd"]
3.通用
Login页面欢迎你
输入的用户名: @Request["username"]
输入的密码: @Request["psd"]
CSS
补充 -- MVC项目引用外部样式的方法
在App_Start文件夹的BundleConfig.cs文件中添加红色内容:
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/mystyle.css",
"~/Content/bootstrap.css",
"~/Content/site.css"));
布局文件_Layout.cshtml(Views/Shared中)使用如下命令:
@Styles.Render("~/Content/css")
代替
JS
补充 -- MVC项目调用外部js文件方法
在App_Start文件夹下的BundleConfig.cs文件中添加代码:
bundles.Add(new ScriptBundle("~/bundles/myjs").Include(
"~/Scripts/my.js"));
然后在当前页面中添加命令:
@Scripts.Render("~/bundles/myjs")
Razor
概述
- Razor是MVC的一个视图模板引擎,它是一种允许向网页中嵌入基于服务器的代码(VB或C#)的标记语法。
- Razor提供了简化的语法表达形式,最大限度地减少语法和多余的字符。
- Razor支持两种文件类型:.cshtml (c#语法)和.vbhtml(vb语法)。
- 在网页加载时,服务器在向浏览器返回页面之前,会先执行页面内的基于服务器代码。
语法规则
- Razor 代码封装于 @{ ... } 中
- 行内表达式(变量和函数)以 @ 开头
- 代码语句以分号结尾
- C# 代码对大小写敏感
- C# 文件的扩展名是 .cshtml
Razor示例
@{
int num1 = 1;
int num2 = 2;
int sum = num1 + num2;
string color ="red";
求和 @num1+@num2=@sum
}
@for (int i = 0; i < 10; i++)
{
第 @i 行
//注意空格,或@(i)
}
Razor 代码封装于 @{ ... } 中,行内表达式以 @ 开头:
@{
string name = "台灯";
}
你好 @name
@DateTime.Now.ToString("yyyy-MM-dd")
@{
string s = "测试文本";
@s
@Html.Raw(s)
//编译后显示
}
@{
int a = 10;
int b = 1;
}
@if(a>b)
{
结果是a>b //错误用法。改为:@:结果是a>b
}
@*
这是一个注释
这个是注释
*@
例如: //可做转移字符
我要输出强大的@@符号
Email地址:[email protected]
其他命令
@Styles.Render():加载css
例如:@Styles.Render("~/Content/css")
@Scripts.Render():加载js
例如:@Scripts.Render("~/bundles/jquery")
@Html.×××():HTML辅助函数
例如:@Html.ActionLink("Back to List", "Index")
MVC Layout布局
@RenderBody()
- 呈现子页的主体内容
- 该方法不需要参数,而且只能出现一次
@RenderPage()
- 呈现指定页面的内容
@RenderSection()
视图中定义节:
@section 节名 {
节的内容
}
布局中显示节:
@RenderSection("节名");
@RenderSection("节名", false);
ORM:Object Relation Mapping 对象关系映射
- ORM是面向对象技术和关系型数据库之间的桥梁,主要实现程序对象到关系数据库数据的映射。
- 程序员使用ORM简洁的API进行对象的读取、修改、保存、删除等操作。ORM则将这些面向对象的操作转换成底层的SQL操作。
- 这样应用程序不再直接访问底层的数据库,而是以面向对象的方式来操作持久化对象。
ADO.NET EF:ADO.NET Entity Framework
- ADO.NET EF是微软开发的基于ADO.NET的ORM框架。
EF技术优势
- 支持多种数据库(SQL Server、Oracle、DB2等)
- 强劲的映射引擎,能很好地支持存储过程;
- 提供Visual Studio集成工具,进行可视化操作;
- 能够与ASP.NET,WPF,WCF Data Services等进行很好的集成;
- 提供LINQ查询数据库。
添加一个EF
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
/*
Code First会默认将诸如ID、Id字段自动设置为主键。
且如果该属性是int类型,Code First还会默认将该列设置为自增长
(Sql Server的Identity类型)。
如果要自定义主键,则在该属性上方添加 [Key]
*/
上下文类
public class StudentDBContext : DbContext
{
public DbSet Students { get; set; }
}
/*
上下文类作用说明:
StudentDBContext 类代表了EF中Student类的数据库上下文,
用来处理获取、存储和更新数据库中的Student类的实例。
*/
using System.Data.Entity; 无法引用问题的解决
当前项目右键 → 管理 NuGet 程序包→ 选择“联机”选项卡中的“nugget.org”→ EntityFramework安装
配置数据库连接(很重要)
在app.config中添加
…
…
- 重要的三点
- Data source=数据库服务器名称是 (LocalDB)\v11.0
- Students.mdf 自定义的SQL Server数据库文件名(mdf)
补充:EF Code First默认规则
- 1、表及列默认规则
EF Code First默认生成的表名为类名的复数形式,表的生成为dbo用户,列名与实体类属性名称相同。 - 2、主键约束
实体类中属性名为Id或[类名]Id,将作为生成表的主键。若主键为int类型,则默认为Sql Server的Identity类型。 - 3、字符类型属性
实体类中string属性,在生成表时,对应Sql Server中nvarchar(max)类型。 - 4、Byte Array类型约束
实体类中byte[]属性,生成表时对应Sql Server中varbinary(max)类型。 - 5、Boolean类型约束
实体类中bool属性,在生成表是对应Sql Server中bit类型。
EF增删改查
- 添加操作
Student stu1 = new Student() { ID = 1, Name = "张飞", Age = 20 };
db.Students.Add(stu1);
db.SaveChanges();
- 删除操作:
Student stuDel = db.Students.Find(1);
db.Students.Remove(stuDel);
db.SaveChanges();
- 修改操作:
Student stu = db.Students.Find(1);
stu.Name = "关羽";
stu.Age = 30;
//db.Entry(stu).State = EntityState.Modified;
db.SaveChanges();
- 查询操作
var result = from item in container
where 条件
[order by 条件]
[group by 条件]
select item;
linq查询操作示例
- 查询1:一般查询,查询所有数据
var result = from u in db.Students
select u;
foreach (var item in result)
{
Console.WriteLine("ID:{0}, 姓名:{1}, 年龄:{2}", item.ID, item.Name, item.Age);
}
扩展方法:var result = db.Students.ToList();
- 查询2:条件查询
var result = from u in db.Students
where u.Age < 22 && u.Name.Contains("张")
select u;
foreach (var item in result)
{
Console.WriteLine("ID:{0}, 姓名:{1}, 年龄:{2}", item.ID, item.Name, item.Age);
}
扩展方法:
var result =
db.Students.Where(u => u.Age < 22 && u.Name.Contains("张"));
- 查询3:模糊查询
var result = from u in db.Students
where SqlFunctions.PatIndex("%飞", u.Name) > 0
select u; //using System.Data.Entity.SqlServer;
foreach (var item in result)
{
Console.WriteLine("ID:{0}, 姓名:{1}, 年龄:{2}", item.ID, item.Name, item.Age);
}
扩展方法:
var result = db.Students.Where(u => SqlFunctions.PatIndex("%飞", u.Name) > 0);
- 查询4:查询单个字段(投影查询)
var result = from p in db.Students
select p.Name;
foreach (var item in result)
{
Console.WriteLine("姓名:{0}", item);
}
扩展方法:
var result = db.Students.Select(p => p.Name);
- 查询5:使用匿名类查询多字段(投影查询)
var result = from p in db.Students
where p.ID < 10
select new { p.ID, p.Name }; //new定义了一个包含ID和Name的匿名类,表示将序列中的每个元素投影到新表中(内存中)
foreach (var item in result)
{
//这里无法输出年龄
Console.WriteLine("ID:{0},姓名:{1}", item.ID, item.Name);
}
扩展方法:
var result = db.Students.Where(p => p.ID < 10) .Select(p => new { p.ID, p.Name });
- 查询5:改动一下
var result = from p in db.Students
where p.ID < 10
select new { BH=p.ID, XM=p.Name };
foreach (var item in result)
{
Console.WriteLine("ID:{0},姓名:{1}", item.BH, item.XM);
}
- 查询6:Top N 查询
var result = (from u in db.Students
orderby u.Age descending //ascending
select u).Take(5);
foreach (var item in result)
{
Console.WriteLine("ID:{0}, 姓名:{1}, 年龄:{2}", item.ID, item.Name, item.Age);
}
扩展方法:
var result = db.Students.Where(u => u.Age < 22).OrderByDescending(u => u.Age).Take(5);
- 查询7:查询第一条/最后一条/第n条
var result = from u in db.Students
where u.Age > 100
select u;
Student stu = result.ToList().FirstOrDefault(); //第一条
//Student stu = result.ToList().LastOrDefault(); //最后一条
//Student stu = result.ToList().ElementAtOrDefault(2); //第3条记录
if(stu!=null) //要判断一下
Console.WriteLine("ID:{0}, 姓名:{1}, 年龄:{2}", stu.ID, stu.Name, stu.Age);
扩展方法:
Student stu = db.Students.ToList().FirstOrDefault();
#######补充:关于First和FirstOrDefault的说明
* First:取序列中满足条件的第一个元素,如果没有元素满足条件,则抛出异常
* FirstOrDefault:取序列中满足条件的第一个元素,如果没有元素满足条件,则返回默认值(对于可以为null的对象,默认值为null,对于不能为null的对象,如int,默认值为0)
* 二者区别在于:当没有元素满足条件时,一个抛出异常,一个返回默认值。 因此,在使用时,一定要注意这个区别:
* 当确信序列中一定有满足条件的元素时,使用First方法,取到元素后,无需判断是否为null
* 当序列中可能找不到满足条件的元素时,使用FirstOrDefault方法,然后,一定要对返回值是否为null,进行不同的处理
方法
* 方法名 如果源序列是空的 源序列只包含一个元素 源序列包含多个元素
* First 抛异常 返回该元素 返回第一个元素
* FirstOrDefault 返回default(TSource) 返回该元素 返回第一个元素
* Last 抛异常 返回该元素 返回最后一个元素
* LastOrDefault 返回default(TSource) 返回该元素 返回最后一个元素
* Single 抛异常 返回该元素 抛异常
* SingleOrDefault 返回default(TSource) 返回该元素 抛异常
- 查询8:使用ToList防止延迟加载,拆分子查询
//这个查询结果可以保存到内存中
var result1 = ( from u in db.Students
where u.Age >= 22
select u).ToList();
var result2 = from u in result1
where u.Name != "赵云"
select u;
foreach (var item in result2)
{
Console.WriteLine("ID:{0}, 姓名:{1}, 年龄:{2}", item.ID, item.Name, item.Age);
}
- 查询9:Count、Sum、Min、Max、Average
int cnt = ( from u in db.Students
where u.Age < 30
select u ).Count(); //统计年龄<30岁人数
// int cnt = (from u in db.Students select u).Count(a => a.Age < 30);
int sum = (from u in db.Students select u.Age).Sum(); //统计总年龄
int max = (from u in db.Students select u.Age).Max(); //统计年龄最大值
double avg = (from u in db.Students select u.Age).Average(); //平均年龄
扩展方法:
int cnt = db.Students.Where(u=> u.Age<30).Count(); 或
int cnt = db.Students.Count(u => u.Age < 30); 更简洁
- 查询10:Distinct、Union、Intersect、Except
示例:
// 将用户角色中的重复角色删除
var roles = user.Roles.Distinct();
//将用户1和用户2的角色合并,并去除重复的角色
var roles = user1.Roles.Union(user2.Roles);
//返回用户1和用户2都具有的角色集合
var roles = user1.Roles.Intersect(user2.Roles);
//返回用户1拥有,而用户2没有的角色集合
var roles = user1.Roles.Except(user2.Roles);
- 查询11:多表联合查询(join)
联合查询SQL语句:
//本例要去掉EF自动生成的主键自增
var result = from u in db.T1s
join p in ( from t in db.T2s
select t )
on u.UserID equals p.UserID //不能用==
select new { u.UserID, u.UserName, p.Dengji };
foreach (var item in result)
{ Console.WriteLine("ID:{0},用户名:{1}, 等级:{2}",
item.UserID, item.UserName, item.Dengji);
}
select * from t1 inner join t2 on t1.userid=t2.userid
- 补充:分页查询
int PageNum; //页码
int CountPerPage = 2; //每页两条数据
//输出第1-2页
for (PageNum = 0; PageNum < 2; PageNum++)
{
var result = db.Students.OrderBy(t => t.ID)
.Skip(PageNum * CountPerPage)
.Take(CountPerPage);
Console.WriteLine("第{0}页:", PageNum + 1);
foreach (var item in result)
{
Console.WriteLine("ID:{0},姓名:{1},年龄:{2}。", item.ID, item.Name, item.Age);
}
Console.WriteLine();
}
- 示例
public class T1
{ [Key] //主键
[DatabaseGenerated(DatabaseGeneratedOption.None)] //不让int类型的主键自增
public int UserID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
public class T2
{ [Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int UserID { get; set; }
public int Jifen { get; set; }
public int Dengji { get; set; }
}
public class StudentDBContext : DbContext
{
public DbSet Students { get; set; }
public DbSet T1s { get; set; }
public DbSet T2s { get; set; }
}
整体
1.控制器Controller:
- 负责响应对MVC网站发起的请求,每一个浏览器请求都映射到一个专门的控制器。
2.Action方法:
- 一般来说,控制器中的public,非static,非重载的方法是Action方法。
- 若不想让某个public方法成为Action方法,可对其使用[NonAction] 属性标记。
控制器示例
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
调用Action
- http://localhost:31215/Home/ //默认为Index方法,Home 为控制器名称
- http://localhost:31215/Home/About //不带参数的Action方法
- http://localhost:31215/movies/details/1 //带参数的Action方法
控制器职责
- 定位并执行Action方法,并确保它能正确执行;
- 获取Action方法所需的参数并传递给它;
- 捕获Action方法执行期间出现的错误;
- 与模型协作,选择一个视图作为用户界面来显示。
3. 视图View:
配合Action方法来显示结果的用户界面。
一般在Action中使用 return View(); 或 return PartialView();返回ActionResult类型时,要定义视图。
4. 模型Model:
用于封装与应用业务逻辑相关的数据,以及用于控制访问和修改这些数据的业务规则。
数据模型可以在控制器和视图之间传递数据。
5. _ViewStart.cshtml
- _ViewStart.cshtml是一个特殊的文件。
- 作用:这个文件会在所有View(.cshtml)被执行之前执行,
- 主要用于一些不方便或不能在布局中进行的统一操作,如为视图指定统一布局。
- @{
Layout = "~/Views/Shared/_Layout.cshtml";
} 为视图指定到布局文件 - _ViewStart.cshtml分为全局和局部两种:
- 全局:所有视图都起作用,位于Views文件下。
- 局部:与视图文件一起位于某个文件夹下,该文件夹下的视图将受局部_ViewStart.cshtml文件作用。