Skip to content

Instantly share code, notes, and snippets.

@iannono
Created January 1, 2013 12:44
Show Gist options
  • Save iannono/4427155 to your computer and use it in GitHub Desktop.
Save iannono/4427155 to your computer and use it in GitHub Desktop.
MVC3: Concise Guide
## 准备工作
[从全新数据库开始](http://msdn.microsoft.com/en-us/data/jj193542)
[从已有的数据库开始](http://msdn.microsoft.com/en-us/data/jj200620)
*值得注意的是需要安装Nuget和Power Tools两个插件,并且保证你的EF是5.0*
## 模型
对于需要返回多个模型到同一个视图的情况,可以采用如下的方式:
//建立新的视图模型
using System;
using System.Collections.Generic;
using GGZBTQPT_PRO.Models;
namespace GGZBTQPT_PRO.ViewModels
{
public class T_ZC_SelectUser
{
public ICollection<T_ZC_User> Users { get; set; }
public ICollection<T_ZC_Department> Departments { get; set; }
public ICollection<T_ZC_Role> Roles { get; set; }
public ICollection<T_ZC_System> Systems { get; set; }
}
}
//视图中的使用
@model GGZBTQPT_PRO.ViewModels.T_ZC_SelectUser
@foreach (var user in Model.Users)
{
<span>@user.Title</span>
}
@foreach (var role in Model.Roles)
{
<span>@role.Title</span>
}
//控制器中的使用
/// <summary>
/// 返回当前角色下的所有用户
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public PartialViewResult SelectUser(int id)
{
Array selected_users = db.T_ZC_Role.Where( r => r.ID == id).First().Users.ToArray();
ViewBag.selected_users = selected_users;
var select_user = new T_ZC_SelectUser();
select_user.Users = db.T_ZC_User.ToList();
select_user.Departments = db.T_ZC_Department.ToList();
return PartialView(select_user);
}
模型中多对多的查询,可以采用如下的方式:
db.Role.Where( r => r.ID == id).First().Users.ToList();
其中Role和User是多对多的关系
写在map中的映射关系对应的是对数据库的操作,在多对多的应用中,只需要编写一边的映射关系即可
## 区域
添加区域后,如何保证路由的正确,需要添加对应的命名空间
//修改Global.asax.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional },// Parameter defaults
new[] { "Web.Controllers" }// 引入默认的命名空间,Web代表项目的名称,请按需修改
);
}
从外部路由到area的写法:
@Html.ActionLink("xxx", "action", "controller", new { area = "area_name"}, null)
## 视图
当控制器范围list的时候,需要在视图中申明集合类型,eg:
`@model Icollection<GGZBTQPT.Models.T_ZC_User`
关于ICollection<>, IEnumerator<>, IList<>,参考[IEnumerator.IEnumerable.ICollection.IList](http://www.cnblogs.com/lenxu/archive/2012/01/09/2316935.html)
当需要在视图中自定义一些展示逻辑的时候,可以通过`@helper`进行封装,eg:
@helper GenerateUser(string selected_users, GGZBTQPT_PRO.Models.T_ZC_User user)
{
if(selected_users.IndexOf(user.ID.ToString()) > 0)
{
<li><a tname="@user.Name" tvalue="@user.ID" checked=true >@user.Name</a></li>
}
else
{
<li><a tname="@user.Name" tvalue="@user.ID" >@user.Name</a></li>
}
}
当需要每个页面实现单独的逻辑的时候,可以通过section进行定义
@RenderSection("name",false)
@section name { // 各自的独立逻辑 }
在超链接中使用action,可以采用@Url.Action
<a class="add" href="@Url.Action("create","ZC_Menu", new { system_id = ViewBag.SystemID})" rel="create" target="dialog" title="添加新的功能菜单" mask="true" width="420" height="340"><span>添加菜单</span></a>
关于dropdownlist
@Html.DropDownList("ParentID", "请选择上级菜单")
new SelectList(db.T_ZC_Menu.Where(p => p.IsValid == true && p.SystemID == system_id), "ID", "Name", t_zc_menu.ParentID);
## 控制器
使用DWZ,控制器的返回值为PartialView,否则,需要在视图页面中添加`layout = null`,用于避免mvc自动添加布局模板
## 常用的对象关系
*一对多*
public class T_ZC_Menu
{
public int ID { get; set; }
public int SystemID { get; set; }
public T_ZC_System System { get; set; }
}
public class T_ZC_System
{
public int ID { get; set; }
public virtual ICollection<T_ZC_Menu> Menus { get; set; }
}
//(Menus)一个系统对应多个功能菜单
this.HasRequired(t => t.System)
.WithMany(s => s.Menus)
.HasForeignKey(t => t.SystemID)
.WillCascadeOnDelete(false);
*多对多*
public class T_ZC_Role
{
public int ID { get; set; }
public virtual ICollection<T_ZC_User> Users { get; set; }
}
public class T_ZC_User
{
public int ID { get; set; }
public ICollection<T_ZC_Role> Roles { get; set; }
}
// (Roles) 每个角色对应多个用户,每个用户对应多个角色
//~~如果需要双向的多对多更新,需要在两边的model映射中都编写相应的映射关系~~
//多对多只需要在其中一边的模型上增加映射关系即可
//Role
this.HasMany(r => r.Users)
.WithMany(u => u.Roles)
.Map(m =>
{
m.ToTable("T_ZC_RoleT_ZC_User");
m.MapLeftKey("T_Role_ID");
m.MapRightKey("T_User_ID");
});
[其他实体关系参考](http://www.cnblogs.com/dudu/tag/Entity%20Framework%20%E5%AE%9E%E8%B7%B5%E7%B3%BB%E5%88%97/)
补充一点:建立双向外键联系(即双向一对一)的时候,需要使用 .WillCascadeOnDelete(false),否则无法操作数据库,参考如下:
public T_HY_MemberMap()
{
// Primary Key
this.HasKey(t => t.ID);
// Properties
this.Property(t => t.ID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.HasRequired(t => t.Person)
.WithMany()
.HasForeignKey(a => a.PersonID)
.WillCascadeOnDelete(true);
}
public T_QY_CorpMap()
{
// Primary Key
this.HasKey(t => t.ID);
// Foreign Key
this.HasRequired(t => t.Member)
.WithMany()
.HasForeignKey(a => a.MemberID)
.WillCascadeOnDelete(false);
}
2012-10-16更新
多对多的这种实体关系只在已经生成的实体上才能应用,也就是说必须是数据库中取出的已有数据所生成的实体,如下的情况是会报错的
var member = new Member();
var favored_item = new Favorite();
favored_item.Members.Add(member); 此时的favored_item.Members为null
//正确的方式应该是:
member.Favorites.Add(favored_item); //此时member.Favorites为null
//多对多删除的时候,对应的级联删除需要手动处理,这是为了避免产生循环删除的问题
## DWZ相关
因为DWZ是一个独立的富客户端框架,基本可以用来替换mvc的布局架构,它通过配置文件自动载入所需的框架信息,包括弹出窗口、tab页等都通过js生成。因此,使用的时候只需在模板页中载入所需的js文件及初始化的js代码,首页中写入整个应用的布局信息。其他的相关功能页面可以采用分部视图的方式进行嵌入,而无需用到其他的模板页。
由于界面部件都是通过js生成的,因此在使用的时候需要注意_通过ajax读取的内容可能需要重复执行一些初始化的js代码,用来为新生成的内容增加js处理事件_;比较典型的就是通过弹出窗口读取模型新增视图的时候,无法执行客户端校验的问题,可以通过如下的方式解决:
<script type="text/javascript">
$.validator.unobtrusive.parse(document);
</script>
在指定rel,使用ajax进行更新的时候,不同的视图,相关的rel名称需要不一样,例如:
<li> @Html.ActionLink(system.Name,"MenuInfo","ZC_Menu",new { system_id = system.ID},new { target = "ajax", rel = "menuInfoBox" })</li>
<li> @Html.ActionLink(department.Name,"UserInfo","ZC_User",new { department_id = department.ID},new { target = "ajax", rel = "userInfoBox" })</li>
在使用ActionLink等help方法的时候,对于传递的routeValues,需要保证key的名称和action中的方法参数名称一致,eg:
<li> @Html.ActionLink(department.Name,"UserInfo","ZC_User",new { department_id = department.ID},new { target = "ajax", rel = "userInfoBox" })</li>
//对应的action方法,也需要使用department_id
public PartialViewResult UserInfo(int department_id)
{
var users = db.T_ZC_User.Include("Department").Where(m => m.DepartmentID == department_id);
return PartialView(users);
}
设置ajaxToDo参数的超链接,和ajax表单一样,通过返回的json串进行回调。如果需要刷新当前navTab,navTabId参数需要返回false,同时默认的navTabAjaxDone方法是没有重载当前tab页的,需要修改dwz.ajax.js
function navTabAjaxDone(json) {
DWZ.ajaxDone(json);
if (json.statusCode == DWZ.statusCode.ok) {
if (json.navTabId) { //把指定navTab页面标记为需要“重新载入”。注意navTabId不能是当前navTab页面的
navTab.reloadFlag(json.navTabId);
} else { //重新载入当前navTab页面
navTab.reload(); #=>加上这句就好了
navTabPageBreak({}, json.rel);
}
if ("closeCurrent" == json.callbackType) {
setTimeout(function () { navTab.closeCurrentTab(); }, 100);
} else if ("forward" == json.callbackType) {
navTab.reload(json.forwardUrl);
}
}
## Migration常用命令
`Enable-Migrations` 用于启用Migration
`Add-Migration migration-name` 用于添加新的migration,该命令会自动比较当前模型中所做的修改,生成对应的数据库操作语句
`Update-Database` 用于将修改更新到数据库
[详细参考](http://msdn.microsoft.com/en-us/data/jj591621)
## Enumberable的一些常用方法
## 资源文件的操作
修改webconfig文件
<system.web>
<globalization uiCulture="auto" culture="auto" enableClientBaseCulture="true"/>
</system.web>
增加App_GlobalResources文件夹,并在该文件夹下增加对应的资源文件;cs文件中的命名空间改为相对应的文件路径,eg:`GGZBTQPT_PRO.App_GlobalResource`
## 关于枚举类型
如果想要使用枚举类型,必须首先保证使用的是vs2012;某些文章里面说到的通过Nuget安装EF5,其实只是安装了其中的一部分特性。而EF5所支持的enum特性,需要.net4.5的支持,而.net4.5不支持vs2010,悲剧啊[参考:](http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/55dc58a4-6190-4bad-b317-1787cf86bf3d)
在下拉菜单中使用枚举类型进行绑定,[参考](http://stackoverflow.com/questions/388483/how-do-you-create-a-dropdownlist-from-an-enum-in-asp-net-mvc)
@Html.DropDownListFor(model => model.Type, new SelectList(Enum.GetNames(typeof(MemberTypes))))
//or in controller, 这里的(int)type实在是让我很困惑的一件事
var types = from MemberTypes type in Enum.GetValues(typeof(MemberTypes))
select new { ID = (int)type, Name = type.ToString() };
ViewData["MemberTypes"] = new SelectList(types, "ID", "Name");
//in view
@Html.DropDownList("MemberTypes")
## 关于测试
入门链接
http://dotnetslackers.com/articles/aspnet/Built-in-Unit-Test-for-ASP-NET-MVC-3-in-Visual-Studio-2010-Part-1.aspx
http://dotnetslackers.com/articles/aspnet/Built-in-Unit-Test-for-ASP-NET-MVC-3-in-Visual-Studio-2010-Part-2.aspx
## 关于Excel生成和读取
生成参考:http://code.google.com/p/excel-generator/wiki/MVC_ExcelResult
读取参考:https://github.com/paulyoder/LinqToExcel#welcome-to-the-linqtoexcel-project
## 一些小技巧
* 通过为字段设置`[Display(Name = "登录名")]`,可以避免在视图中编写额外的labelText
* action中传递的参数名是不分大小写的
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment