http://www.cnblogs.com/nuaalfm/archive/2009/11/11/1600811.html

预备知识:

1、了解反射技术

2、了解C#3.0中扩展方法,分布类,Linq to object,Linq to sql

3、了解ASP.NET MVC

在项目中每添加一个表往往都要添加一套增删改代码,而且这些代码很多情况下都很相似,这里我们给出一个通用的解决方案供大家参考。

一、准备工作:

这里我们先要在数据库中添加两个表News和User如下图:然后拖到dbml中生成实体类。

这里我们先准备一个接口:ICommonTable

Code
public  interface ICommonTable
    {
        int id { get; set; }
    }

然后让News和User实体都继承于此接口


Code
 public partial class News : ICommonTable
    {     }
    public partial class User : ICommonTable
    {
       
    }

二、通用删除操作

分别添加NewsList.aspx和UserList.aspx两个view,添加方式参见ASP.NET MVC实践系列2-简单应用

在这两个View中加入删除链接:

<%= Html.ActionLink("删除", "Delete", new { key = item.id, partialName="News" })%>

<%= Html.ActionLink("删除", "Delete", new { key = item.id, partialName="User" })%>
然后添加一个Controller:

 public ActionResult Delete(string partialName, int? key)
        {
            RepositoryBase repositoryBase = new RepositoryBase(partialName);
            repositoryBase.Delete(key ?? 0);
            return RedirectToAction(partialName + "List");//返回到list
        }
接下来我们介绍一下RepositoryBase :

   public class RepositoryBase
    {
        public Type EntityType { get; private set; }
        public RepositoryBase(string entityType)
        {
            Type type = GetBllTypeByName(entityType);             EntityType = type;
        }
        public ICommonTable CreateNew()
        {
            return (ICommonTable)Activator.CreateInstance(EntityType);
        }
        /// <summary>
        /// 通过字符串获得其Type
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        private static Type GetBllTypeByName(string typeName)
        {
            Type type = null;
            var ass = AppDomain.CurrentDomain.GetAssemblies()
                 .Where(p => p.FullName.Contains("CommonCEDemo"));
            foreach (var a in ass)
            {
                type = a.GetTypes().Where(p => p.Name == typeName).FirstOrDefault();
                if (type != null)
                    break;
            }             if (type == null)
            {
                throw new Exception("类型未定义:" + typeName);
            }
            return type;
        }
        public RepositoryBase(Type entityType)
        {
            EntityType = entityType;
        }
        public ICommonTable Get(int id)
        {
            DBDataContext db = Context.GetContext();
            return db.GetTable(EntityType).Cast<ICommonTable>().FirstOrDefault(p => p.id == id);
        }
        public void Delete(int id)
        {
            ICommonTable bllTable = Get(id);
            Context.GetContext().GetTable(EntityType).DeleteOnSubmit(bllTable);
            Context.GetContext().SubmitChanges();
        }
       
    }
 
这里边重点要理解的就是GetBllTypeByName方法。有了这个方法我们就可以动态的通过名字获得相应的Type了。这里还有个问题就是DataContext是从何而来的,我们这里为了简单起见全程声明了一个DataContext没有考虑多线程的情况

public class Context
{
    static DBDataContext context;
    static Context()
    {
        if (context==null)
        {
            context = new DBDataContext();
        }
    }
    public static DBDataContext GetContext()
    {
        return context;
    }
}
 

有个这些当我们想要对一个表进行删除是只要添加相应的链接就可以了(如<%= Html.ActionLink("删除", "Delete", new { key = item.id, partialName="News" })%>)

三、通用增加、修改
首先添加一个CreateEditView.aspx视图
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <%Html.RenderPartial(ViewData["PartialName"].ToString()); %>

</asp:Content>
然后添加两个Partial视图News.ascx和User.ascx,这两个视图是分别基于News和User类的强类型视图,具体内容参加源码。
接下来我们添加相应的Controller

 public ActionResult CreateEditView(string partialName, int? key)
        {             ViewData["PartialName"] = partialName;             RepositoryBase repositoryBase = new RepositoryBase(partialName);
            ICommonTable table;
            if (key == null)
            {
                table = repositoryBase.CreateNew();
            }
            else
            {
                table = repositoryBase.Get(key ?? 0);
            }             return View("CreateEditView", table);
        }         [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult CreateEditView(string partialName, int? key, FormCollection formCollection)
        {
            RepositoryBase repositoryBase = new RepositoryBase(partialName);
            ICommonTable bllTable;
            if (key == null)
            {
                bllTable = repositoryBase.CreateNew();
            }
            else
            {
                bllTable = repositoryBase.Get(key ?? 0);
            }             this.UpdateModel(bllTable, true);
            if (key == null)
            {
                Context.GetContext().GetTable(repositoryBase.EntityType).InsertOnSubmit(bllTable);             }             Context.GetContext().SubmitChanges();             return RedirectToAction(partialName+"List");//返回到list
        }
 
这里边大家可能有疑问的就是this.UpdateModel(bllTable, true);这个方法在mvc框架中并不存在,这是我添加的扩展方法,这个地方如果使用UpdateModel(bllTable)虽然编译不会报错,但也没有更新成功,查了一下mvc的源码,问题就出在如下源码中:

 protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IDictionary<string, ValueProviderResult> valueProvider) where TModel : class {
            if (model == null) {
                throw new ArgumentNullException("model");
            }
            if (valueProvider == null) {
                throw new ArgumentNullException("valueProvider");
            }             Predicate<string> propertyFilter = propertyName => BindAttribute.IsPropertyAllowed(propertyName, includeProperties, excludeProperties);
            IModelBinder binder = Binders.GetBinder(typeof(TModel));             ModelBindingContext bindingContext = new ModelBindingContext() {
                Model = model,
                ModelName = prefix,
                ModelState = ModelState,
                ModelType = typeof(TModel),
                PropertyFilter = propertyFilter,
                ValueProvider = valueProvider
            };
            binder.BindModel(ControllerContext, bindingContext);
            return ModelState.IsValid;
        }
 

这个typeof(TModel)造成了只会更新声明类型中有的属性,把它换成model.GetType()就可以解决问题了,我扩这的这个方法如下


public static class ControllerExtension
    {
        /// <summary>
        /// 更新时是否按照当前类型进行更新
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="controller"></param>
        /// <param name="model"></param>
        /// <param name="isEx"></param>
        public static void UpdateModel<TModel>(this Controller controller, TModel model, bool isExtension) where TModel : class
        {
            if (isExtension)
            {
                Predicate<string> propertyFilter = propertyName => IsPropertyAllowed(propertyName, null, null);
                IModelBinder binder = ModelBinders.Binders.GetBinder(model.GetType());                 ModelBindingContext bindingContext = new ModelBindingContext()
                {
                    Model = model,
                    ModelName = null,
                    ModelState = controller.ModelState,
                    ModelType = model.GetType(),
                    PropertyFilter = propertyFilter,
                    ValueProvider = controller.ValueProvider
                };
                binder.BindModel(controller.ControllerContext, bindingContext);             }
            else
            {
                throw new Exception("isExtension不能选择false");
            }
        }
        private static bool IsPropertyAllowed(string propertyName, string[] includeProperties, string[] excludeProperties)
        {
            bool includeProperty = (includeProperties == null) || (includeProperties.Length == 0) || includeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);
            bool excludeProperty = (excludeProperties != null) && excludeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);
            return includeProperty && !excludeProperty;
        }
    }
 

有了这些,当我们想对新表进行编辑和添加时只需要添加相应的Partial编辑视图就可以了,简化了我们的编程工作。

四、缺点
1、须要按照规则命名,比方说Partial视图需要以相应的类名来命名
2、页面引用是弱类型的
 

在ASP.NET MVC中对表进行通用的增删改的更多相关文章

  1. 【转载】ASP.NET MVC Web API 学习笔记---联系人增删改查

    本章节简单介绍一下使用ASP.NET MVC Web API 做增删改查.目前很多Http服务还是通过REST或者类似RESP的模型来进行数据操作的.下面我们通过创建一个简单的Web API来管理联系 ...

  2. ASP.NET MVC Web API 学习笔记---联系人增删改查

    本章节简单介绍一下使用ASP.NET MVC Web API 做增删改查. 目前很多Http服务还是通过REST或者类似RESP的模型来进行数据操作的. 下面我们通过创建一个简单的Web API来管理 ...

  3. 3、ASP.NET MVC入门到精通——Entity Framework增删改查

    这里我接上讲Entity Framework入门.从网上下载Northwind数据库,新建一个控制台程序,然后重新添加一个ado.net实体数据模型. EF中操作数据库的"网关"( ...

  4. asp.net mvc 三层加EF 登录注册 增删改查

    首先打开vs软件新建项目创建web中的mvc项目再右击解决方案创建类库项目分别创建DAL层和BLL层再把DAL层和BLL层的类重命名在mvc项目中的Models文件夹创建model类在DAL创建ADO ...

  5. Asp.net mvc中的Ajax处理

    在Asp.net MVC中的使用Ajax, 可以使用通用的Jquery提供的ajax方法,也可以使用MVC中的AjaxHelper. 这篇文章不对具体如何使用做详细说明,只对于在使用Ajax中的一些需 ...

  6. ASP.NET MVC 中使用 AjaxFileUpload 插件时,上传图片后不能显示(预览)

    AjaxFileUpload 插件是一个很简洁很好用的上传文件的插件,可以实现异步上传功能,但是在 ASP.NET MVC中使用时,会出现上传图片后不能正确的显示的问题,经过仔细排查,终于找到原因,解 ...

  7. 在ASP.NET MVC 中获取当前URL、controller、action 、参数

    URL的获取很简单,ASP.NET通用:[1]获取 完整url (协议名+域名+虚拟目录名+文件名+参数) string url=Request.Url.ToString(); [2]获取 虚拟目录名 ...

  8. ASP.NET MVC中注册Global.asax的Application_Error事件处理全局异常

    在ASP.NET MVC中,通过应用程序生命周期中的Application_Error事件可以捕获到网站引发的所有未处理异常.本文作为学习笔记,记录了使用Global.asax文件的Applicati ...

  9. 2.ASP.NET MVC 中使用Crystal Report水晶报表

    上一篇,介绍了怎么导出Excel文件,这篇文章介绍在ASP.NET MVC中使用水晶报表. 项目源码下载:https://github.com/caofangsheng93/CrystalReport ...

随机推荐

  1. Docker部署Golang

    1. 安装docker 2. mkdir myDocker 3.  cd myDocker && touch Dockerfile 4.  Dockerfile写入 # 将golang ...

  2. python2.7 倒计时

    From: http://www.vitostack.com/2016/06/05/python-clock/#more Python公告 Python 发布了一个网站 http://pythoncl ...

  3. 20135313-exp1

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计 班级:1353 姓名:吴子怡 学号:20135313 成绩:            指导教师:娄嘉鹏  实 ...

  4. <!CDATA[]]用法详解

    所有 XML 文档中的文本均会被解析器解析. 只有 CDATA 区段(CDATA section)中的文本会被解析器忽略. PCDATA PCDATA 指的是被解析的字符数据(Parsed Chara ...

  5. 手机访问本地php项目遇到的问题及解决

    做html5的本地应用要调试后台,学了下php 按照和连j2ee的时候一样,电脑发射wifi,ipconfig..等等  发现tomcat的可以访问,apache的不能访问,搜索好久,没找到解答, j ...

  6. shiro+springmvc 都使用缓存

    基于涛哥shiro案例16 的这时候要配置service方法的缓存 在spring-config.xml添加 <context:annotation-config /> <cache ...

  7. Journal entry of the eleventh chapter to chapter twelfth

    第十一章:正如很多人一样,觉得软件工程这个课程好像没什么用,感觉提高不了自己的写代码能力,学的都是理论知识,好像对于我们这种技术类的专业离得有点远,是这样的吗? 第十二章:每样东西都没有完美的,即使我 ...

  8. java中的互斥锁和信号量的区别

    互斥锁和信号量都是操作系统中为并发编程设计基本概念,互斥锁和信号量的概念上的不同在于,对于同一个资源,互斥锁只有0和1 的概念,而信号量不止于此.也就是说,信号量可以使资源同时被多个线程访问,而互斥锁 ...

  9. [51单片机] Keil C51中变量的使用方法详解

    引言    8051内核单片机是一种通用单片机,在国内占有较大的市场份额.在将C语言用于51内核单片机的研究方面,Keil公司做得最为成功.由于51内核单片机的存储结构的特殊性,Keil C51中变量 ...

  10. Scrum 项目7.0——第一个Sprint的总结和读后感

          总结: 通过这一次的Sprint,我了解了Sprint的整个流程,也学会了编制backlog,也了解了在软件工程中,一个团队的任务是怎么样分配和一个项目是怎么样开展的.从对软件工程的认识只 ...