在ASP.NET MVC中对表进行通用的增删改

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、页面引用是弱类型的

五、源码下载

时间: 2024-10-08 08:15:58

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

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

本章节简单介绍一下使用ASP.NET MVC Web API 做增删改查.目前很多Http服务还是通过REST或者类似RESP的模型来进行数据操作的.下面我们通过创建一个简单的Web API来管理联系人 说明:为了方便数据不使用真正的数据库,而是通过内存数据模拟 1.       Web API中包含的方法 Action HTTP method Relative URI GetAllContact GET /api/contact GetContact GET /api/contact /id

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

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 这里我接上讲Entity Framework入门.从网上下载Northwind数据库,新建一个控制台程序,然后重新添加一个ado.net实体数据模型. EF中操作数据库的"网关"(操作上下文) DBContext封装 .NET Fra

关于asp.net MVC 中的TryUpdateModel方法

有比较才会有收货,有需求才会发现更多. 在传统的WebFormk开发工作中,我们常常会存在如下的代码块 //保存 protected void btnSubmit_Click(object sender, EventArgs e) { try { BLL.MoneyBll cun = new BLL.MoneyBll(); Model.Money m1 = new Model.Money(); m1.Commany = int.Parse(this.Commany.Text); m1.Count

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

在ASP.NET MVC中,通过应用程序生命周期中的Application_Error事件可以捕获到网站引发的所有未处理异常.本文作为学习笔记,记录了使用Global.asax文件的Application_Error事件处理和捕获全局异常的详细步骤. 文章演示项目是使用vs2013编译器编写的,下载地址:GlobalExceptionHandle-By-Application_Error.zip. 在VS2013中新建一个MVC项目,这里要先关闭自定义错误,将Web.config配置文件中cus

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

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

如何在ASP.NET MVC 中获取当前URL、controller、action

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

asp.net mvc中换肤机制类库 ThemedViewEngines

制作blog系统或者通用cms系统的时候,我们经常会用到Theme功能.asp.net mvc中的一种实现方式,是继承实现RazorViewEngine即可. 这是在GitHub中找到的一个示例:https://github.com/benedict-chan/ThemedViewEngines 结构如下图: 实现的核心代码ThemedRazorViewEngine.cs: 1 using System; 2 using System.Web.Mvc; 3 4 namespace ThemedV

log4net 使用总结- (2)在ASP.NET MVC 中使用

log4net在ASP.NET MVC中的配置,还有一种配置方式,即不在web.config中,而是单独新建一个log4net.config 在根目录下 第一.引用log4net.dll 第二.在站点根目录下增加log4net.config <?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="

ASP.NET MVC中使用异步控制器

线程池 一直想把项目改写成异步,但是ASP.NETMVC3下写的过于繁琐,.NET 4.5与ASP.NET MVC下代码写起来就比较简单了, MS好像也一直喜欢这样搞,每一个成熟的东西,都要演变好几个版本,才能趋于规范. ASP.NET MVC 中为什么需要使用异步呢,IIS有一个线程池来处理用户的请求,当一个新的请求过来时,将调度池中的线程以处理该请求,然而,但并发量很高的情况下,池中的线程已经不能够满足这么多的请求时候,池中的每一个线程都处于忙的状态则在处理请求时将阻塞处理请求的线程,并且该