首次使用.Net MVC5的一点总结
最近做了个.Net MVC相关的小项目,创下本人代码史上多个第一。第一次使用MVC5,第一次使用Razor,第二次使用EintityFramework且第一次体验code first,第一次使用Bootstrap…
关于Entity Framework和code first
首先,DbContext看上去和System.Data.Linq的DataContext看上去有点像,DbSet仿佛也对应着Table,但对DbSet并不能像对Table那样直接调用Linq的扩展方法查询,而必须首先调用DbSet.ToList(),然后才能调用Linq的扩展方法。否则会抛出"innner error"异常。这是Linq to Entity 和 Linq to Sql 的一个不同。
其次,如果采用code first 方式建模,那最好彻底放弃任何与db first有关的思维,包括在数据库里定义视图。网上虽然有一些一边采用code first建模一边用db first方式将数据库视图映射为Entity对象的文章。尽管这次我也这么做了,但这已经偏离了code first创立的本意。
code first 没有提供关于数据库视图映射的任何技术,并不是code first 疏忽或者遗漏了视图这一重要的数据库对象,而是刻意摒弃了它。
T-SQL中的Translation,关系映射,在数据库里很重要的一方面就体现在视图对象。但在code first中, Translation体现在对象成员的封装中。
例如,省-市关系,
//省
public class Province
{
//主键
[Key]
public virtual int Id { get; set; }
//代码
public virtual int Code { get; set; }
//名称
public virtual string Name { get; set; }
}
//市
public class City
{
//主键
[Key]
public virtual int Id { get; set; }
//所属的省
public virtual Province Province { get; set; }
//名称
public virtual string Name { get; set; }
}
在这段代码中,省-市关系体现为省Province作为市City的一个属性(可以理解为字段成员)。如果要用Linqu to Entity 查询山东省的所有城市,代码如下:
public IEnumberable<City> GetCitiesByProvice(string name)
{
return DbContext.Set<City>().ToList<City>().Where(v=> "山东" == v.Province.name);
}
从查询效果上,这与下面的数据库中的sql查询是等效的:
select * from (select City.*, Province.Code, Province.[Name] AS ProvinceName from City inner join Province on City.ProvinceId = Province.Id) where Province.[Name] ='山东'
也就是说,Entity Framework已经将这段连接查询的sql语句封装起来,不再需要程序员关心。而其中的连接查询:"select … from … inner join … on …"恰恰就是City-Province视图的定义语句
Create View CityView As
select City.*, Province.Code, Province.[Name] AS ProvinceName from City inner join Province on City.ProvinceId = Province.Id;
T-Sql中,定义一个视图,仿佛定义了一个函数;查询一个视图,仿佛调用一个函数。而这个工作,在code first 模式下,Entity Framework框架已经替我们做了。尽管我们在数据库中找不到视图,也找不到函数。所以,使用code first,完全不必考虑数据库中的视图查询,底层的工作,框架已经做了。
尽管如此,如果code first 的连接查询是通过命令的方式,首先建立与数据库的连接实现的,所以每查询一次,就会通过网络打开一次连接,发送一次命令,这中间当然还存在软件的端口通信。但如果采用db first,无论是视图还是函数都已定义好,通过命令直接调用,在高并发大访问量的情况下,效率肯定会高些。而采用code first 的好处,在于提高开发和维护效率,缩短开发周期。
说到维护,不能不提code first 的数据迁移。修改模型的字段,除了高效,还是高效。
比如,想把City类对象的Name字段改为CityName字段,先在.cs源代码文件中改好并保存,最好编译一下。然后打开NuGet包管理器控制台,输入数据迁移命令,然后再输入Update-Database -Force,一个回车,数据库中City表的相关字段同时也随之发生改变。
当然,如果采用了code first,同时又添加了db first 的视图映射到Entity模型,那数据迁移对该视图没有任何作用,如果不手动修改视图定义,那就坐等Exception吧。
form验证和跳转url
MVC5的Identity验证看上去相当不错,不过时间太短我还没消化。但老一套的,复习一下也不错。
- FormsAuthentication和MemberShip是两回事,MemberShipProvider只提供用户表中的信息,FormsAuthentication票证还是需要FormsAuthentication来签发。
- 如果设置了form验证,要在身份验证后跳转回原先被限制访问的页面,需要在验证表单的form中必须提供ReturnUrl字段的值。否则参数无法传递到验证Action中,页面无法跳转。
关于Cookie
在HttpContext.Current.Response中写入的cookie,在客户端只读,无法写入。这一点,有时容易忘。
高效强大的Bootstrap
BootStrap的网格系统和媒体查询非常高效,只指定像class=“col-md-x col-xs-y"就可以在不同终端自由切换布局。无需再搞一个“电脑版”+“手机版”。需要注意的是,一旦使用了col-xx-push-m, col-xx-n,m+n<=12,否则row会溢出。
另外,BootStrap提供的控件也相当丰富,集成度比较高,一个"class=”,就解决了大部分前端样式的设计。