从头开始一步一步实现EF6+Autofac+MVC5+Bootstar…
2018-06-23 23:21:08来源:未知 阅读 ()
本来是想试着做一个简单OA项目玩玩的,真是不做不知道,一做吓死人,原来以为很简单的事情,但是做起来不是忘这就是忘那的,有的技术还得重新温习。所以还是得记录。免得哪天电脑挂了,就全没有了。
开始是看了园子里何镇汐的一系列文章,写的太好了,只看了几篇就有想写代码的冲动,很大一部分都是搬他的东西。但是我还是领误不了DDD,所以先就着三层搞搞。
我搞了两个解决方案,一个本着是想做框架,把有通用的封装了,以后要用就引dll,由于太枯燥,另一个就是想做个玩具项目,两边轮流搞搞
先是dll部分的,当然很多都没实现反正是自己的,以后再慢慢补,我这里东西很少,所以没用文件夹之类的,全部直接一个命名空间
先是autofac封装类,只是简单封装了一下,做玩具够用,跟上一篇博客一样的,这里不说了
using Autofac; using System; namespace MTF.Domain { public class DependencyContainer { public static IContainer Container { get { return container; } } public static IContainer container; private DependencyContainer() { } public static void Initializer(Action<ContainerBuilder> action) { ContainerBuilder builder = new ContainerBuilder(); if (action != null) { action(builder); container = builder.Build(); } } private static void Error() { if (container == null) throw new InvalidOperationException("容器没有初始化"); else return; } public static TService Resolve<TService>() { return container.Resolve<TService>(); } } }
BaseEntity 的设计是参考何兄的,大家可以去看他的文章,写的太好了,这里几乎是搬的
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace MTF.Domain { public abstract class BaseEntity<TKey> : IEntity<TKey> { #region 初始化 public TKey GId { get; private set; } protected BaseEntity(TKey id) { this.GId = id; validationRules = new List<IValidationRule>(); } #endregion #region 实体相等性比较 public override bool Equals(object obj) { if (obj == null) return false; if (!(obj is BaseEntity<TKey>)) return false; return this == (BaseEntity<TKey>)obj; } public override int GetHashCode() { return this.GId.GetHashCode(); } public static bool operator ==(BaseEntity<TKey> entity1, BaseEntity<TKey> entity2) { if ((object)entity1 == null || (object)entity2 == null) return false; if (entity1.GId == null) return false; if (entity1.GId.Equals(default(TKey))) return false; return entity1.GId.Equals(entity2.GId); } public static bool operator !=(BaseEntity<TKey> entity1, BaseEntity<TKey> entity2) { return !(entity1 == entity2); } #endregion #region 验证、验证规则添加及验证处理 private List<IValidationRule> validationRules;//验证结果集合 private ICollection<ValidationResult> validationResults;//验证规则集合 private IValidationHandler validationHandler;//验证处理器 private void DefaultValidtae() { validationResults = new List<ValidationResult>(); ValidationContext context = new ValidationContext(this, null, null); Validator.TryValidateObject(this, context, validationResults, true);//默认验证实体特性注解 if (validationRules.Count > 0)//如果有其它验证规则 { validationRules.ForEach(o => { if (o.Validate() == ValidationResult.Success || o.Validate() == null) return; //其它规则不通过时 validationResults.Add(o.Validate());//添加到验证结果集合 }); } } /// <summary> /// 验证标识 /// </summary> public virtual bool IsValid { get { DefaultValidtae(); return validationResults.Count <= 0; } } /// <summary> /// 添加验证规则 /// </summary> /// <param name="rule"></param> public void AddValidationRule(IValidationRule rule) { if (rule == null) return; validationRules.Add(rule); } /// <summary> /// 默认验证当前实体方法 /// </summary> public virtual void Validate() { if (IsValid) return; //验证不通过时 try { validationHandler = DependencyContainer.Resolve<IValidationHandler>();//设置验证处理器 } catch { throw new InvalidOperationException("当前实体没有通过验证,但未设置验证处理器,请检查容器是否注入"); } validationHandler.Handle(validationResults);//处理验证结果 } #endregion } }
Repository数据操作接口,这里也是搬的,但有一点不一样,考虑到排序我不想用Guid类型的,所以没有约束Entity必须实现IBaseEntity接口或者聚合根,因为我用的三层,没用聚合根,再者我在后面的Service层想用到分页排序,看到后面应该就能理解的。但是我并不知道这样对不对
IUnitOfWork只搞了一个方法,以后再搞
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace MTF.Domain { public interface IRepository<TEntity,TKey> where TEntity:class { /// <summary> /// 添加单个实体 /// </summary> /// <param name="entity"></param> void Add(TEntity entity); /// <summary> /// 添加实体集合 /// </summary> /// <param name="entities"></param> void Add(IEnumerable<TEntity> entities); /// <summary> /// 修改 /// </summary> /// <param name="entity"></param> void Update(TEntity entity); /// <summary> /// 根据Id删除实体 /// </summary> /// <param name="id"></param> void Remove(TKey id); /// <summary> /// 删除实体 /// </summary> /// <param name="entity"></param> void Remove(TEntity entity); /// <summary> /// 查找实体列表 /// </summary> /// <returns></returns> List<TEntity> FindAll(); /// <summary> /// 查找实体列表 /// </summary> /// <returns></returns> IQueryable<TEntity> Find(); /// <summary> /// 查找实体列表 /// </summary> /// <param name="ids"></param> /// <returns></returns> //List<TEntity> Find(IEnumerable<TKey> ids); /// <summary> /// 根据Id查找实体 /// </summary> /// <param name="id"></param> /// <returns></returns> TEntity Find(params object[] id); /// <summary> /// 判断实体是否存在 /// </summary> /// <param name="predicate"></param> /// <returns></returns> bool Exists(Expression<Func<TEntity, bool>> predicate); /// <summary> /// 索引器查找 /// </summary> /// <param name="id"></param> /// <returns></returns> TEntity this[TKey id] { get; } /// <summary> /// 保存 /// </summary> void Save(); /// <summary> /// 获取工作单元 /// </summary> /// <returns></returns> IUnitOfWork GetUnitOfWork(); IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> where); } }
using System; namespace MTF.Domain { public interface IUnitOfWork:IDisposable { void Commit(); } }
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace MTF.Domain { public interface IValidationHandler { void Handle(ICollection<ValidationResult> validationResults); } }
using System.ComponentModel.DataAnnotations; namespace MTF.Domain { public interface IValidationRule { ValidationResult Validate(); } }
Domain现在只完成了这么多,其它的接口还没搞,还是以后再搞,懒的。
后面是EF部分了,引用Domain层
简单的工作单元
using MTF.Domain; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Data.Entity.Validation; namespace MTF.EFDatas { public class EFUnitOfWork :DbContext, IUnitOfWork { protected EFUnitOfWork(string connection) : base(connection) { } public void Commit() { try { SaveChanges(); } catch(DbUpdateConcurrencyException) { throw; } catch(DbEntityValidationException) { throw; } } } }
简单的EF数据操作,还是以后慢慢再搞
using MTF.Domain; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace MTF.EFDatas { public class EFRepository<TEntity,TKey>: IRepository<TEntity,TKey> where TEntity:class { protected EFUnitOfWork unitOfWork { get; private set; } public EFRepository() { this.unitOfWork = DependencyContainer.Resolve<EFUnitOfWork>(); } public void Add(TEntity entity) { unitOfWork.Set<TEntity>().Add(entity); } public void Add(IEnumerable<TEntity> entities) { unitOfWork.Set<TEntity>().AddRange(entities); } public void Update(TEntity entity) { unitOfWork.Entry(entity).State = System.Data.Entity.EntityState.Modified; } public void Remove(TKey id) { unitOfWork.Set<TEntity>().Remove(Find(id)); } public void Remove(TEntity entity) { unitOfWork.Set<TEntity>().Remove(entity); } public List<TEntity> FindAll() { return Find().ToList(); } public IQueryable<TEntity> Find() { return unitOfWork.Set<TEntity>(); } //public List<TEntity> Find(IEnumerable<TKey> ids) //{ // if (ids == null) // return null; // return Find().Where(o => ids.Contains(o.GId)).ToList(); //} public TEntity Find(params object[] id) { return unitOfWork.Set<TEntity>().Find(id); } public IQueryable<TEntity> Find(Expression<Func<TEntity,bool>> where) { return Find().Where(where); } public bool Exists(Expression<Func<TEntity, bool>> predicate) { return unitOfWork.Set<TEntity>().Any(predicate); } public TEntity this[TKey id] { get { return Find(id); } } public void Save() { unitOfWork.Commit(); } public IUnitOfWork GetUnitOfWork() { return unitOfWork; } } }
这里我自己写了一个分页类EF专用的,因为不想一定要用ID分类,所以加了个泛型类型,专门用于排序用的,本来想着这个类是专门给service用的,不应该用public的,但是想着以后别的地方可能会用到,所以还是公共了
using System; using System.Data.Entity; using System.Linq; using System.Linq.Expressions; namespace MTF.EFDatas { /// <summary> /// 分页 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <typeparam name="TOrder">要排序的类型</typeparam> public class Pager<TEntity,TOrder> where TEntity : class { public Pager(DbContext eow) { this.unitOfWork = eow; this.total = eow.Set<TEntity>().Count(); Initia(1, 20); } private DbContext unitOfWork; public int PageIndex { get { return pageIndex; } } private int pageIndex; public int PageCount { get { return pageCount; } } private int pageCount; public int Total { get { return total; } } private int total; public int PageSize { get { return pageSize; } } private int pageSize; public int Skip { get { return skip; } } private int skip; public int Take { get { return take; } } private int take; private void Initia(int index, int size) { if (index < 1) index = 1; if (size >= total) { pageIndex = 1; pageCount = 1; pageSize = total; skip = 0; take = pageSize; } if (size < total) { int n = total % size; int x = total / size; if (n == 0) { pageSize = size; pageCount = x; if (index > pageCount) { index = PageCount; pageIndex = index; } pageIndex = index; skip = (pageIndex - 1) * size; take = size; } else { pageCount = x + 1; if (index > pageCount) { pageIndex = pageCount; } else { pageIndex = index; } if (pageIndex == pageCount) { pageIndex = PageCount; pageSize = n; skip = (pageIndex - 1) * size; take = n; } else { pageSize = size; skip = (pageIndex - 1) * size; take = size; } } } } public void SetPageSize(int size) { pageSize = size; Initia(PageIndex, PageSize); } public IQueryable<TEntity> GetPageList(Expression<Func<TEntity, TOrder>> order) { return unitOfWork.Set<TEntity>().OrderBy(order).Skip(Skip).Take(Take); } public IQueryable<TEntity> GetPageList(int pageIndex, Expression<Func<TEntity, TOrder>> order) { this.pageIndex = pageIndex; Initia(PageIndex, PageSize); return GetPageList(order); } public IQueryable<TEntity> GetPageList(int pageIndex, int pageSize, Expression<Func<TEntity, TOrder>> order) { this.pageIndex = pageIndex; this.pageSize = pageSize; Initia(PageIndex, PageSize); return GetPageList(order); } } }
直接给代码先,都是很简单,不知道合不合理,这里用到了Pager类,当作属性使用,客户端得到Service就可以使用它的,它们共用一个工作单元
using MTF.Domain; using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Linq.Expressions; namespace MTF.EFDatas { public class BaseService<TEntity,TKey,TOrderPage> where TEntity:class { private IRepository<TEntity, TKey> Repository; private Pager<TEntity, TOrderPage> pager; public Pager<TEntity,TOrderPage> Pager { get { return pager; } } public BaseService() { Repository = DependencyContainer.Resolve<IRepository<TEntity, TKey>>(); pager = new Pager<TEntity, TOrderPage>(DependencyContainer.Resolve<EFUnitOfWork>()); } public void Add(TEntity entity) { Repository.Add(entity); } public void Add(IEnumerable<TEntity> entities) { Repository.Add(entities); } public void Update(TEntity entity) { Repository.Update(entity); } public void Remove(TKey id) { Repository.Remove(id); } public void Remove(TEntity entity) { Repository.Remove(entity); } public List<TEntity> FindAll() { return Repository.FindAll(); } public IQueryable<TEntity> Find() { return Repository.Find(); } //public List<TEntity> Find(IEnumerable<TKey> ids) //{ // return Repository.Find(ids); //} public TEntity Find(params object[] id) { return Repository.Find(id); } public IQueryable<TEntity> Find(Expression<Func<TEntity,bool>> where) { return Find().Where(where); } public bool Exists(Expression<Func<TEntity, bool>> predicate) { return Repository.Exists(predicate); } public TEntity this[TKey id] { get { return Find(id); } } public void Save() { Repository.Save(); } } }
由于没有写测试代码,写到这里的时候 我都有点迫不及待想试试了,所以就先到此生成。另外写一个MVC试试呗,搞个三层玩玩
DataModel层添加上面的DLL引用,我叫MTF指的是My Test Frame呵呵,不会英语,反正是搞的玩。
安装EF和AUTOFAC包开搞,先搞个BaseEntity,由于我int 类型不会初始化的时候赋值,
但是又不想GUID来排序,所以我想的办法是实体接口的时候,给的GId的属性名,主键我还是用的int类型,Guid初始化的时候赋值,它同样是唯一的,方便内存操作,int类型做自增的主键,在插入数据库后才有值。
做了三个类,用户,权限和角色,还有三个中间类,以配多对多关系,本着学习的精神,我用的CodeFirst和F..Api(不会定这个单词了,晕)方式配置映射
一样的简单玩玩的,可能还没有注释,直接上了
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using MTF.Domain; namespace OADemo.DataModel.Domains { public class EntityBase:BaseEntity<Guid> { protected EntityBase(Guid id) : base(id) { }//guid类型的属性以后应该可以用到,它是在初始化的时候赋值的,内存中好找 public EntityBase() : this(Guid.NewGuid())//int类型映射主键,插入数据库时才有值,方便数据库不方便内存操作 { SubTime = DateTime.Now;//提交时间为当前时间 IsDeleted = false;//这个好像有点多余,默认应该就是false,但不确定,所以加上了 } //子类共有的属性 public int Id { get; set; } public bool IsDeleted { get; set; } public DateTime SubTime { get; set; } public string Remark { get; set; } } }
using System.Collections.Generic; namespace OADemo.DataModel.Domains { public class UserEntity:EntityBase { public ICollection<UserRole> UserRoles { get; set; } = new List<UserRole>();//导航属性 public ICollection<UserPermission> UserPermissions { get; set; } = new List<UserPermission>();//导航属性 public string Name { get; set; } public int Age { get; set; } public string Email { get; set; } public string RealName { get; set; } } public class RoleEntity:EntityBase { public ICollection<UserRole> UserRoles { get; set; } = new List<UserRole>(); public ICollection<RolePermission> RolePermissions { get; set; } = new List<RolePermission>(); public string Name { get; set; } public string Description { get; set; } } public class Permission:EntityBase { public ICollection<UserPermission> UserPermissions { get; set; } = new List<UserPermission>(); public ICollection<RolePermission> RolePermissions { get; set; } = new List<RolePermission>(); public string Name { get; set; } public string Url { get; set; } public string HttpMethod { get; set; } } public class UserRole:EntityBase { public UserEntity User { get; set; }//显示外键属性 public RoleEntity Role { get; set; } public int UserId { get; set; } public int RoleId { get; set; } } public class UserPermission:EntityBase { public UserEntity User { get; set; } public int UserId { get; set; } public Permission Permission { get; set; } public int PermissionId { get; set; } } public class RolePermission:EntityBase { public RoleEntity Role { get; set; } public int RoleId { get; set; } public Permission Permission { get; set; } public int PermissionId { get; set; } } }
配置映射
using System.Data.Entity.ModelConfiguration; namespace OADemo.DataModel.Domains.Maps { public class EntityMap<T>:EntityTypeConfiguration<T> where T:EntityBase { public EntityMap() { this.HasKey(o => o.Id);//指定主键,这个类没多大必要,代码不多也是本着学习的目的玩 this.Ignore(o => o.IsValid); } } }
namespace OADemo.DataModel.Domains.Maps { public class UserRoleMap:EntityMap<UserRole> { public UserRoleMap() { //指定导航属性和外键,配置多对多关系 this.HasRequired(o => o.User).WithMany(o => o.UserRoles).HasForeignKey(o => o.UserId); this.HasRequired(o => o.Role).WithMany(o => o.UserRoles).HasForeignKey(o => o.RoleId); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace OADemo.DataModel.Domains.Maps { public class UserPermissionMap:EntityMap<UserPermission> { public UserPermissionMap() { this.HasRequired(o => o.User).WithMany(o => o.UserPermissions).HasForeignKey(o => o.UserId); this.HasRequired(o => o.Permission).WithMany(o => o.UserPermissions).HasForeignKey(o => o.PermissionId); } } }
namespace OADemo.DataModel.Domains.Maps { public class RolePermissionMap:EntityMap<RolePermission> { public RolePermissionMap() { this.HasRequired(o => o.Role).WithMany(o => o.RolePermissions).HasForeignKey(o => o.RoleId); this.HasRequired(o => o.Permission).WithMany(o => o.RolePermissions).HasForeignKey(o => o.PermissionId); } } }
namespace OADemo.DataModel.Domains.Maps { public class UserMap:EntityMap<UserEntity> { public UserMap() { this.Property(o => o.Name).IsRequired().HasMaxLength(30); this.Property(o => o.Age).IsRequired(); this.Property(o => o.Email).IsRequired().HasMaxLength(100); this.Property(o => o.RealName).HasMaxLength(30); } } }
namespace OADemo.DataModel.Domains.Maps { public class RoleMap:EntityMap<RoleEntity> { public RoleMap() { this.Property(o => o.Name).IsRequired().HasMaxLength(50); this.Property(o => o.Description).HasMaxLength(200); } } }
namespace OADemo.DataModel.Domains.Maps { public class PermissionMap:EntityMap<Permission> { public PermissionMap() { this.Property(o => o.Url).IsRequired(); this.Property(o => o.HttpMethod).IsRequired().HasMaxLength(30); } } }
数据库上下文,也可以说是工作单元
using System.Data.Entity; using MTF.EFDatas; using System.Data.Entity.ModelConfiguration.Conventions; using OADemo.DataModel.Domains.Maps; namespace OADemo.DataModel.Domains { public class OADemoDataContext:EFUnitOfWork { public OADemoDataContext() : base("OADemoDataContext") { } public DbSet<UserEntity> User { get; set; } public DbSet<RoleEntity> Role { get; set; } public DbSet<Permission> Permission { get; set; } public DbSet<UserRole> UserRole { get; set; } public DbSet<UserPermission> UserPermission { get; set; } public DbSet<RolePermission> RolePermission { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Configurations.Add(new UserMap()); modelBuilder.Configurations.Add(new RoleMap()); modelBuilder.Configurations.Add(new UserRoleMap()); modelBuilder.Configurations.Add(new UserPermissionMap()); modelBuilder.Configurations.Add(new PermissionMap()); modelBuilder.Configurations.Add(new RolePermissionMap()); base.OnModelCreating(modelBuilder); } } }
到此,EFCodefirst最基本的配置应该就是这样了,下面是服务层了同样引用DLL,DataModel层和安装相关的包,代码很少,就几个空类,主要是继承了父类
using MTF.EFDatas; using OADemo.DataModel.Domains; using System; namespace OADemo.BLL { public class UserBll:BaseService<UserEntity,Guid,int> { } public class RoleBll : BaseService<RoleEntity, Guid, int> { } public class PermissionBll : BaseService<Permission, Guid, int> { } public class UserRoleBll : BaseService<UserRole, Guid, int> { } public class UserPermissionBll : BaseService<UserPermission, Guid, int> { } public class RolePermissionBll : BaseService<RolePermission, Guid, int> { } }
好了,准备就绪,下面到了MVC了,这里我还没真正开始呢,还只是相当于测试前面的工作,开玩,还是引用装包先。
在GlobalApplication_Start()方法,也就是程序开处,注入必要的依赖,贯穿整个生命周期
using System.Web.Mvc; using System.Web.Routing; using Autofac; using MTF.EFDatas; using OADemo.DataModel.Domains; using OADemo.BLL; using MTF.Domain; namespace OADemo.MVCApp { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { DependencyContainer.Initializer(o => { o.RegisterType<OADemoDataContext>().As<EFUnitOfWork>().InstancePerLifetimeScope(); o.RegisterGeneric(typeof(EFRepository<,>)).As(typeof(IRepository<,>)).InstancePerLifetimeScope(); o.RegisterType<UserBll>(); }); AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); } } }
还要配置AppConfig文件指定数据链接,这里就不展示了。
先搞个控制器,测试服务层,主要是看看分页部分
里面有注释,不多说了,这里用到了json.net,需要安装包,另外封装了一个表格html文本的帮助类,放在Common层在
using System.Linq; using System.Web.Mvc; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Text; using OADemo.Common; namespace OADemo.MVCApp.Controllers { public class HomeController : Controller { //找到相关实体的服务,这里我之前插入500多条数据 private UserBll userService = DependencyContainer.Resolve<UserBll>(); //把分页类当全局属性用 private Pager<UserEntity,int> Pager { get { return userService.Pager; } } // GET: Home public ActionResult Index() { ViewBag.PageSize = Pager.PageSize;//初始值在Pager类中已经有默认的初始值 ViewBag.PageCount = Pager.PageCount; return View(); } /// <summary> /// 展示表格,类名取的不地道,懒的改了 /// </summary> /// <param name="pageIndex">当前选中的页码 应该也做成可空类型,懒的改</param> /// <param name="pageSize">当前页的表格行数</param> /// <returns></returns> public ActionResult InitiaTable(int pageIndex,int? pageSize) { //配置可空类型,如果前台没有数据传来,给一个默认值 int size =(int)( pageSize == null ? 20 : pageSize); //根据前台参数取得相应的数据 var users=Pager.GetPageList(pageIndex, size, o => o.Id).ToList(); //配置json格式的html文本,传给前台 var result = JsonStringHelper.GetTbodyJObjectStrin(users, new string[] { "Name", "Age", "RealName", "Email" }); return Content(result.ToString()); } /// <summary> /// 设置每页展示的行数 /// </summary> /// <param name="pageSize"></param> /// <returns></returns> public ActionResult SetPageSize(int? pageSize) { int size = (int)(pageSize==null?20:pageSize); Pager.SetPageSize(size); var jo = new JObject(new JProperty("pageCountJson", Pager.PageCount),new JProperty("pageSizeJson",size)); return Content(jo.ToString()); } } }
using System.Collections.Generic; using System.Text; using Newtonsoft.Json.Linq; namespace OADemo.Common { public class JsonStringHelper { /// <summary> /// 通过反射将列表中指定的属性值装配成多行多列的Html文本 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="list"></param> /// <param name="propertyNames">要输出的属性名</param> /// <returns></returns> public static string GetTbodyHtmlString<T>(List<T> list, params string[] propertyNames) { StringBuilder sb = new StringBuilder(); list.ForEach(o => { sb.Append(@"<tr>");//做一个行的开始 List<string> values = new List<string>();//存放符合条件的值 var properties = o.GetType().GetProperties();//得到当前实体类型的所有属性 foreach (var property in properties) { if (propertyNames != null) { foreach (var name in propertyNames) { if (property.Name.Contains(name)) values.Add(property.GetValue(o).ToString()); } } } values.ForEach(v => { sb.AppendFormat(@"<td>{0}</td>", v);//加入列 }); sb.Append(@"</tr>");//行结束 }); return sb.ToString(); } /// <summary> /// 通过反射将列表中指定的属性值装配成多行多列的json格式的Html文本 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="list"></param> /// <param name="propertyNames"></param> /// <returns></returns> public static JObject GetTbodyJObjectStrin<T>(List<T> list, params string[] propertyNames) { return new JObject(new JProperty("tbodyJson", GetTbodyHtmlString(list, propertyNames))); } } }
前台用的bootstrap,做了个基本的表格展示 数据,分页用的是jqPaginator插件,前端还不会封装,对JQ不是很熟,作了注释的
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="~/Content/bootstrap.min.css" rel="stylesheet" /> <script src="~/scripts/jquery-1.9.1.min.js"></script> <script src="~/scripts/bootstrap.min.js"></script> <script src="~/scripts/jqPaginator.min.js"></script> <script type="text/javascript"> $(function () { var pageCount= @ViewBag.PageCount;//总页数,初始值从后台获取(全局变量) var nPageSize= @ViewBag.PageSize;//每页显示的行数,初始值从后台获取(全局变量) //jqPaginator插件,初始化分页 $.jqPaginator('#pager', { totalPages: pageCount,//总页数 visiblePages: 10,//分页条中显示的条数 currentPage: 1,//默认选中的页码 first: '<li class="prev"><a href="javascript:;">首页</a></li>', prev: '<li class="prev"><a href="javascript:;">上一页</a></li>', next: '<li class="next"><a href="javascript:;">下一页</a></li>', page: '<li class="page"><a href="javascript:;">{{page}}</a></li>', last: '<li class="page"><a href="javascript:;">尾页</a></li>', //换页事件,参数num为当前选中的页码,type指示是否是通过点击 onPageChange: function (num, type) { $("#table tbody").empty();//先将tbody清空 var tbodyHtml = "";//变量:tbody的html代码 //Ajax异步发送数据到后台 $.post("/Home/InitiaTable/", { pageIndex: num,// pageSize: "20"//默认为20条 }, //Ajax回调函数 InitiaTable ) } }); //btnSetPageSize点击事件 $("#btnSetPageSize").click(function(){ //还是Ajax的post与后台交互 $.post("/Home/SetPageSize/",//请求页面 {pageSize:$("#pageSize").val()},//传递参数 //回调函数 SetPageSize ); }); }); //参数data为后台传来装配好的tbody的html文本 function InitiaTable (data) { var json = eval("(" + data + ")");//转换为json格式 var tbodyHtml = json.tbodyJson; //获取html $("#table tbody").append(tbodyHtml);//添加到tbody中 } //参数data为后台传来的总页数 function SetPageSize(data){ nPageSize=$("#pageSize").val();//重新加载当前选中页的行数 var json=eval("(" + data + ")");//接收后台数据,转换成json格式 pageCount = json.pageCountJson;//加载总页数,以传递给jqPaginator插件 //重新加载jqPaginator插件(对JQ不熟,不会封装的痛苦,复制的……) $.jqPaginator('#pager', { totalPages: pageCount, visiblePages: 10, currentPage: 1, first: '<li class="prev"><a href="javascript:;">首页</a></li>', prev: '<li class="prev"><a href="javascript:;">上一页</a></li>', next: '<li class="next"><a href="javascript:;">下一页</a></li>', page: '<li class="page"><a href="javascript:;">{{page}}</a></li>', last: '<li class="page"><a href="javascript:;">尾页</a></li>', onPageChange: function (num, type) { $("#table tbody").empty(); var tbodyHtml = ""; $.post("/Home/InitiaTable/", { pageIndex: num, pageSize: nPageSize }, InitiaTable ) } }); } </script> <title>Index</title> </head> <body> <div class="container text-center" > <div class="row" > <div class="col-md-12"> <table class="table" id="table"> <thead> <tr> <td>Name</td> <td>Age</td> <td>RealName</td> <td>Email</td> </tr> </thead> <tbody> </tbody> </table> </div> </div> <div class="row"> <div class="col-md-8"> <ul id="pager" class="pagination"> <li> </li> </ul> </div> <div class="col-md-4 " style="margin-top:25px"> <label for="pageSize" >设置每页行数</label> <input type="text" style="width:25px" id="pageSize" /> <button type="button" class="btn-info" id="btnSetPageSize">设置</button> </div> </div> </div> </body> </html>
看看效果,开始进入时,展示默认数据
我这里一共有501条数据,现在默认的是每页20条,点尾页,看看一共有多少页
设置每页13行
点尾页看看总页数
到此,我认为测试圆满结束,全部合格。但是最后我才发现数据多了一行。应该是JsonStringHelper类中的这句if (property.Name.Contains(name))有问题,属性名里包含了相同的字符串???这是我发表了之后才发现,现在太晚了,把这个改成if (property.Name==name)应该是没有问题的了。但是对这种相对硬的编码我还是有点感觉不爽。先就这样吧,太晚了。明天还在做苦力活啊,我都不是做这行的,不知道为什么 要熬夜写这些
未成品下载:http://pan.baidu.com/s/1o84Cegy
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:最简洁的跨线程控件调用
- position: sticky实现导航栏下滑吸顶效果 2020-05-30
- Vue 结合html2canvas和jsPDF实现html页面转pdf 2020-04-25
- 10.布局:两栏和主区域在后的三栏布局,实现侧边栏和主区域伪 2020-04-12
- 5.通过定位实现二级菜单 2020-04-10
- HTML + CSS 布局实现全屏布局 2020-04-10
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash