快速业务通道

ASP.NET MVC教程:数据库表的增删改

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-03-14

预备知识:

1、了解反射技术

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

3、了解ASP.NET MVC

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

一、准备工作:

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

ASP.NET MVC教程:数据库表的增删改

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

public  interface ICommonTable
    {
        
int id { getset; }
    }

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

 public partial class News : ICommonTable
    {

    }
    
public partial class User : ICommonTable
    {
       
    }

二、通用删除操作

分别添加NewsList.aspx和UserList.aspx两个view。

在这两个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 { getprivate 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, nullnull);
                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、页面引用是弱类型的

五、源码下载

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号