預備知識:
1、了解反射技術
2、了解C#3.0中擴展方法,分布類,Linq to object,Linq to sql
3、了解ASP.Net MVC
在項目中每添加一個表往往都要添加一套增刪改代碼,而且這些代碼很多情況下都很相似,這裡我們給出一個通用的解決方案供大家參考。
一、准備工作:
這裡我們先要在數據庫中添加兩個表News和User如下圖:然後拖到dbml中生成實體類。
這裡我們先准備一個接口:ICommonTable
public interface ICommonTable然後讓News和User實體都繼承於此接口
public partial class News : 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 { 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">然後添加兩個Partial視圖News.ascx和User.ascx,這兩個視圖是分別基於News和User類的強類型視圖,具體內容參加源碼。
接下來我們添加相應的Controller
public ActionResult CreateEditVIEw(string partialName, int? key)這裡邊大家可能有疑問的就是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、頁面引用是弱類型的