ASP.NET MVC中如何实现针对任意表的通用增删改操作?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1313个文字,预计阅读时间需要6分钟。
了解反演技术:1、掌握基本原理;2、学习应用案例。
预备知识:
1、了解反射技术
2、了解C#3.0中扩展方法,分布类,Linq to object,Linq to sql
3、了解ASP.NET MVC
在项目中每添加一个表往往都要添加一套增删改代码,而且这些代码很多情况下都很相似,这里我们给出一个通用的解决方案供大家参考。
一、准备工作:
这里我们先要在数据库中添加两个表News和User如下图:然后拖到dbml中生成实体类。
这里我们先准备一个接口:ICommonTable
CodepublicinterfaceICommonTable
{
intid{get;set;}
}
然后让News和User实体都继承于此接口
CodepublicpartialclassNews:ICommonTable
{
}
publicpartialclassUser: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:
{
RepositoryBaserepositoryBase=newRepositoryBase(partialName);
repositoryBase.Delete(key??0);
returnRedirectToAction(partialName+"List");//返回到list
} 接下来我们介绍一下RepositoryBase: publicclassRepositoryBase
{
publicTypeEntityType{get;privateset;}
publicRepositoryBase(stringentityType)
{
Typetype=GetBllTypeByName(entityType);
EntityType=type;
}
publicICommonTableCreateNew()
{
return(ICommonTable)Activator.CreateInstance(EntityType);
}
///<summary>
///通过字符串获得其Type
///</summary>
///<paramname="typeName"></param>
///<returns></returns>
privatestaticTypeGetBllTypeByName(stringtypeName)
{
Typetype=null;
varass=AppDomain.CurrentDomain.GetAssemblies()
.Where(p=>p.FullName.Contains("CommonCEDemo"));
foreach(varainass)
{
type=a.GetTypes().Where(p=>p.Name==typeName).FirstOrDefault();
if(type!=null)
break;
}
if(type==null)
{
thrownewException("类型未定义:"+typeName);
}
returntype;
}
publicRepositoryBase(TypeentityType)
{
EntityType=entityType;
}
publicICommonTableGet(intid)
{
DBDataContextdb=Context.GetContext();
returndb.GetTable(EntityType).Cast<ICommonTable>().FirstOrDefault(p=>p.id==id);
}
publicvoidDelete(intid)
{
ICommonTablebllTable=Get(id);
Context.GetContext().GetTable(EntityType).DeleteOnSubmit(bllTable);
Context.GetContext().SubmitChanges();
}
} 这里边重点要理解的就是GetBllTypeByName方法。有了这个方法我们就可以动态的通过名字获得相应的Type了。这里还有个问题就是DataContext是从何而来的,我们这里为了简单起见全程声明了一个DataContext没有考虑多线程的情况 publicclassContext
{
staticDBDataContextcontext;
staticContext()
{
if(context==null)
{
context=newDBDataContext();
}
}
publicstaticDBDataContextGetContext()
{
returncontext;
}
} 有个这些当我们想要对一个表进行删除是只要添加相应的链接就可以了(如<%= Html.ActionLink("删除", "Delete", new { key = item.id, partialName="News" })%>) 三、通用增加、修改 首先添加一个CreateEditView.aspx视图 <asp:ContentID="Content2"ContentPlaceHolderID="MainContent"runat="server">
<%Html.RenderPartial(ViewData["PartialName"].ToString());%>
</asp:Content> 然后添加两个Partial视图News.ascx和User.ascx,这两个视图是分别基于News和User类的强类型视图,具体内容参加源码。 接下来我们添加相应的Controller publicActionResultCreateEditView(stringpartialName,int?key)
{
ViewData["PartialName"]=partialName;
RepositoryBaserepositoryBase=newRepositoryBase(partialName);
ICommonTabletable;
if(key==null)
{
table=repositoryBase.CreateNew();
}
else
{
table=repositoryBase.Get(key??0);
}
returnView("CreateEditView",table);
}
[AcceptVerbs(HttpVerbs.Post)]
publicActionResultCreateEditView(stringpartialName,int?key,FormCollectionformCollection)
{
RepositoryBaserepositoryBase=newRepositoryBase(partialName);
ICommonTablebllTable;
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();
returnRedirectToAction(partialName+"List");//返回到list
}
这里边大家可能有疑问的就是this.UpdateModel(bllTable, true);这个方法在mvc框架中并不存在,这是我添加的扩展方法,这个地方如果使用UpdateModel(bllTable)虽然编译不会报错,但也没有更新成功,查了一下mvc的源码,问题就出在如下源码中: protectedinternalboolTryUpdateModel<TModel>(TModelmodel,stringprefix,string[]includeProperties,string[]excludeProperties,IDictionary<string,ValueProviderResult>valueProvider)whereTModel:class{
if(model==null){
thrownewArgumentNullException("model");
}
if(valueProvider==null){
thrownewArgumentNullException("valueProvider");
}
Predicate<string>propertyFilter=propertyName=>BindAttribute.IsPropertyAllowed(propertyName,includeProperties,excludeProperties);
IModelBinderbinder=Binders.GetBinder(typeof(TModel));
ModelBindingContextbindingContext=newModelBindingContext(){
Model=model,
ModelName=prefix,
ModelState=ModelState,
ModelType=typeof(TModel),
PropertyFilter=propertyFilter,
ValueProvider=valueProvider
};
binder.BindModel(ControllerContext,bindingContext);
returnModelState.IsValid;
} 这个typeof(TModel)造成了只会更新声明类型中有的属性,把它换成model.GetType()就可以解决问题了,我扩这的这个方法如下 publicstaticclassControllerExtension
{
///<summary>
///更新时是否按照当前类型进行更新
///</summary>
///<typeparamname="TModel"></typeparam>
///<paramname="controller"></param>
///<paramname="model"></param>
///<paramname="isEx"></param>
publicstaticvoidUpdateModel<TModel>(thisControllercontroller,TModelmodel,boolisExtension)whereTModel:class
{
if(isExtension)
{
Predicate<string>propertyFilter=propertyName=>IsPropertyAllowed(propertyName,null,null);
IModelBinderbinder=ModelBinders.Binders.GetBinder(model.GetType());
ModelBindingContextbindingContext=newModelBindingContext()
{
Model=model,
ModelName=null,
ModelState=controller.ModelState,
ModelType=model.GetType(),
PropertyFilter=propertyFilter,
ValueProvider=controller.ValueProvider
};
binder.BindModel(controller.ControllerContext,bindingContext);
}
else
{
thrownewException("isExtension不能选择false");
}
}
privatestaticboolIsPropertyAllowed(stringpropertyName,string[]includeProperties,string[]excludeProperties)
{
boolincludeProperty=(includeProperties==null)||(includeProperties.Length==0)||includeProperties.Contains(propertyName,StringComparer.OrdinalIgnoreCase);
boolexcludeProperty=(excludeProperties!=null)&&excludeProperties.Contains(propertyName,StringComparer.OrdinalIgnoreCase);
returnincludeProperty&&!excludeProperty;
}
} 有了这些,当我们想对新表进行编辑和添加时只需要添加相应的Partial编辑视图就可以了,简化了我们的编程工作。 四、缺点 1、须要按照规则命名,比方说Partial视图需要以相应的类名来命名 2、页面引用是弱类型的 五、源码下载
本文共计1313个文字,预计阅读时间需要6分钟。
了解反演技术:1、掌握基本原理;2、学习应用案例。
预备知识:
1、了解反射技术
2、了解C#3.0中扩展方法,分布类,Linq to object,Linq to sql
3、了解ASP.NET MVC
在项目中每添加一个表往往都要添加一套增删改代码,而且这些代码很多情况下都很相似,这里我们给出一个通用的解决方案供大家参考。
一、准备工作:
这里我们先要在数据库中添加两个表News和User如下图:然后拖到dbml中生成实体类。
这里我们先准备一个接口:ICommonTable
CodepublicinterfaceICommonTable
{
intid{get;set;}
}
然后让News和User实体都继承于此接口
CodepublicpartialclassNews:ICommonTable
{
}
publicpartialclassUser: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:
{
RepositoryBaserepositoryBase=newRepositoryBase(partialName);
repositoryBase.Delete(key??0);
returnRedirectToAction(partialName+"List");//返回到list
} 接下来我们介绍一下RepositoryBase: publicclassRepositoryBase
{
publicTypeEntityType{get;privateset;}
publicRepositoryBase(stringentityType)
{
Typetype=GetBllTypeByName(entityType);
EntityType=type;
}
publicICommonTableCreateNew()
{
return(ICommonTable)Activator.CreateInstance(EntityType);
}
///<summary>
///通过字符串获得其Type
///</summary>
///<paramname="typeName"></param>
///<returns></returns>
privatestaticTypeGetBllTypeByName(stringtypeName)
{
Typetype=null;
varass=AppDomain.CurrentDomain.GetAssemblies()
.Where(p=>p.FullName.Contains("CommonCEDemo"));
foreach(varainass)
{
type=a.GetTypes().Where(p=>p.Name==typeName).FirstOrDefault();
if(type!=null)
break;
}
if(type==null)
{
thrownewException("类型未定义:"+typeName);
}
returntype;
}
publicRepositoryBase(TypeentityType)
{
EntityType=entityType;
}
publicICommonTableGet(intid)
{
DBDataContextdb=Context.GetContext();
returndb.GetTable(EntityType).Cast<ICommonTable>().FirstOrDefault(p=>p.id==id);
}
publicvoidDelete(intid)
{
ICommonTablebllTable=Get(id);
Context.GetContext().GetTable(EntityType).DeleteOnSubmit(bllTable);
Context.GetContext().SubmitChanges();
}
} 这里边重点要理解的就是GetBllTypeByName方法。有了这个方法我们就可以动态的通过名字获得相应的Type了。这里还有个问题就是DataContext是从何而来的,我们这里为了简单起见全程声明了一个DataContext没有考虑多线程的情况 publicclassContext
{
staticDBDataContextcontext;
staticContext()
{
if(context==null)
{
context=newDBDataContext();
}
}
publicstaticDBDataContextGetContext()
{
returncontext;
}
} 有个这些当我们想要对一个表进行删除是只要添加相应的链接就可以了(如<%= Html.ActionLink("删除", "Delete", new { key = item.id, partialName="News" })%>) 三、通用增加、修改 首先添加一个CreateEditView.aspx视图 <asp:ContentID="Content2"ContentPlaceHolderID="MainContent"runat="server">
<%Html.RenderPartial(ViewData["PartialName"].ToString());%>
</asp:Content> 然后添加两个Partial视图News.ascx和User.ascx,这两个视图是分别基于News和User类的强类型视图,具体内容参加源码。 接下来我们添加相应的Controller publicActionResultCreateEditView(stringpartialName,int?key)
{
ViewData["PartialName"]=partialName;
RepositoryBaserepositoryBase=newRepositoryBase(partialName);
ICommonTabletable;
if(key==null)
{
table=repositoryBase.CreateNew();
}
else
{
table=repositoryBase.Get(key??0);
}
returnView("CreateEditView",table);
}
[AcceptVerbs(HttpVerbs.Post)]
publicActionResultCreateEditView(stringpartialName,int?key,FormCollectionformCollection)
{
RepositoryBaserepositoryBase=newRepositoryBase(partialName);
ICommonTablebllTable;
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();
returnRedirectToAction(partialName+"List");//返回到list
}
这里边大家可能有疑问的就是this.UpdateModel(bllTable, true);这个方法在mvc框架中并不存在,这是我添加的扩展方法,这个地方如果使用UpdateModel(bllTable)虽然编译不会报错,但也没有更新成功,查了一下mvc的源码,问题就出在如下源码中: protectedinternalboolTryUpdateModel<TModel>(TModelmodel,stringprefix,string[]includeProperties,string[]excludeProperties,IDictionary<string,ValueProviderResult>valueProvider)whereTModel:class{
if(model==null){
thrownewArgumentNullException("model");
}
if(valueProvider==null){
thrownewArgumentNullException("valueProvider");
}
Predicate<string>propertyFilter=propertyName=>BindAttribute.IsPropertyAllowed(propertyName,includeProperties,excludeProperties);
IModelBinderbinder=Binders.GetBinder(typeof(TModel));
ModelBindingContextbindingContext=newModelBindingContext(){
Model=model,
ModelName=prefix,
ModelState=ModelState,
ModelType=typeof(TModel),
PropertyFilter=propertyFilter,
ValueProvider=valueProvider
};
binder.BindModel(ControllerContext,bindingContext);
returnModelState.IsValid;
} 这个typeof(TModel)造成了只会更新声明类型中有的属性,把它换成model.GetType()就可以解决问题了,我扩这的这个方法如下 publicstaticclassControllerExtension
{
///<summary>
///更新时是否按照当前类型进行更新
///</summary>
///<typeparamname="TModel"></typeparam>
///<paramname="controller"></param>
///<paramname="model"></param>
///<paramname="isEx"></param>
publicstaticvoidUpdateModel<TModel>(thisControllercontroller,TModelmodel,boolisExtension)whereTModel:class
{
if(isExtension)
{
Predicate<string>propertyFilter=propertyName=>IsPropertyAllowed(propertyName,null,null);
IModelBinderbinder=ModelBinders.Binders.GetBinder(model.GetType());
ModelBindingContextbindingContext=newModelBindingContext()
{
Model=model,
ModelName=null,
ModelState=controller.ModelState,
ModelType=model.GetType(),
PropertyFilter=propertyFilter,
ValueProvider=controller.ValueProvider
};
binder.BindModel(controller.ControllerContext,bindingContext);
}
else
{
thrownewException("isExtension不能选择false");
}
}
privatestaticboolIsPropertyAllowed(stringpropertyName,string[]includeProperties,string[]excludeProperties)
{
boolincludeProperty=(includeProperties==null)||(includeProperties.Length==0)||includeProperties.Contains(propertyName,StringComparer.OrdinalIgnoreCase);
boolexcludeProperty=(excludeProperties!=null)&&excludeProperties.Contains(propertyName,StringComparer.OrdinalIgnoreCase);
returnincludeProperty&&!excludeProperty;
}
} 有了这些,当我们想对新表进行编辑和添加时只需要添加相应的Partial编辑视图就可以了,简化了我们的编程工作。 四、缺点 1、须要按照规则命名,比方说Partial视图需要以相应的类名来命名 2、页面引用是弱类型的 五、源码下载

