从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现
本来是想试着做一个简单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>();
}
}
}
Dependency类代码
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);//默认验证实体特性注解
)//如果有其它验证规则
{
validationRules.ForEach(o =>
{
if (o.Validate() == ValidationResult.Success || o.Validate() == null)
return;
//其它规则不通过时
validationResults.Add(o.Validate());//添加到验证结果集合
});
}
}
/// <summary>
/// 验证标识
/// </summary>
public virtual bool IsValid { get
{
DefaultValidtae();
;
} }
/// <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;
}
}
}
}
EFUnitOfWork
简单的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;
}
}
}
EFRepository
这里我自己写了一个分页类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(, );
}
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)
{
)
index = ;
if (size >= total)
{
pageIndex = ; pageCount = ; pageSize = total; skip = ; take = pageSize;
}
if (size < total)
{
int n = total % size; int x = total / size;
)
{
pageSize = size;
pageCount = x;
if (index > pageCount)
{
index = PageCount;
pageIndex = index;
}
pageIndex = index;
skip = (pageIndex - ) * size;
take = size;
}
else
{
pageCount = x + ;
if (index > pageCount)
{
pageIndex = pageCount;
}
else
{
pageIndex = index;
}
if (pageIndex == pageCount)
{
pageIndex = PageCount;
pageSize = n;
skip = (pageIndex - ) * size;
take = n;
}
else
{
pageSize = size;
skip = (pageIndex - ) * 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
直接给代码先,都是很简单,不知道合不合理,这里用到了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();
}
}
}
BaseService
由于没有写测试代码,写到这里的时候 我都有点迫不及待想试试了,所以就先到此生成。另外写一个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; }
}
}
EntityBase
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; }
}
}
Entities
配置映射
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);
}
}
}
EntityMap
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);
}
}
}
UserRoleMap
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);
}
}
}
UserPermissionMap
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);
}
}
}
RolePermissionMap
namespace OADemo.DataModel.Domains.Maps
{
public class UserMap:EntityMap<UserEntity>
{
public UserMap()
{
);
this.Property(o => o.Age).IsRequired();
);
);
}
}
}
UserMap
namespace OADemo.DataModel.Domains.Maps
{
public class RoleMap:EntityMap<RoleEntity>
{
public RoleMap()
{
);
);
}
}
}
RoleMap
namespace OADemo.DataModel.Domains.Maps
{
public class PermissionMap:EntityMap<Permission>
{
public PermissionMap()
{
this.Property(o => o.Url).IsRequired();
);
}
}
}
PermissionMap
数据库上下文,也可以说是工作单元
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);
}
}
}
OADemoDataContext
到此,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>
{
}
}
EntityService
好了,准备就绪,下面到了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);
}
}
}
Application_Start()
还要配置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)
{
//配置可空类型,如果前台没有数据传来,给一个默认值
: 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)
{
: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)));
}
}
}
表格html帮助类代码
前台用的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: ,//分页条中显示的条数
currentPage: ,//默认选中的页码
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条
},
//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: ,
currentPage: ,
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
从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现的更多相关文章
- 从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简前后台ajax表格展示及分页(二)前端修改、添加表格行点击弹出模态框
在前一篇中,由于不懂jquery,前端做的太差了,今天做稍做修改,增加一个跳转到指定页面功能,表格行点击样式变化.并且在表格中加入bootstarp的按钮组,按钮点击后弹出模态框,须修改common, ...
- 一步一步实现MVC5+EF6+Bootstarp+Autofac+NoSql实现OADemo 之登陆(一) 验证码 Captcha 之大插件小用
不知何年何月才能完成OADemo啊,总之还是一步一步来吧,这段时间开始着手了,先做登陆. 前段时间研究了一下在CentOS7下安装Mysql和Memcached服务,并测试了用C#操作,结果还行. ...
- 【DG】[三思笔记]一步一步学DataGuard
[DG][三思笔记]一步一步学DataGuard 它有无数个名字,有人叫它dg,有人叫它数据卫士,有人叫它data guard,在oracle的各项特性中它有着举足轻理的地位,它就是(掌声)..... ...
- WCF 一步一步 发布 WCF服务 到 IIS (图)
WCF 一步一步 发布 WCF服务 到 IIS (图) 使用VS自带的WCFSVCHost(WCF服务主机)发布WCF服务,时刻开发人员测试使用. 下面我们来看一下如何在IIS中部发布一个WCF服务. ...
- 一步一步构建手机WebApp开发——页面布局篇
继上一篇:一步一步构建手机WebApp开发——环境搭建篇过后,我相信很多朋友都想看看实战案例,这一次的教程是页面布局篇,先上图: 如上图所示,此篇教程便是教初学者如何快速布局这样的页面.废话少说,直接 ...
- 一步一步教你在 Android 里创建自己的账号系统(一)
大家假设喜欢我的博客,请关注一下我的微博,请点击这里(http://weibo.com/kifile),谢谢 转载请标明出处(http://blog.csdn.net/kifile),再次感谢 大家在 ...
- 如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑
阅读目录 前言 场景1的思考 场景2的思考 避坑方式 实践 结语 一.前言 在上一篇中(如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成),有一行注释的代码: public interfa ...
- 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成
阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...
- 如何一步一步用DDD设计一个电商网站(十)—— 一个完整的购物车
阅读目录 前言 回顾 梳理 实现 结语 一.前言 之前的文章中已经涉及到了购买商品加入购物车,购物车内购物项的金额计算等功能.本篇准备把剩下的购物车的基本概念一次处理完. 二.回顾 在动手之前我对之 ...
随机推荐
- 升级WebService图形服务,将K10.2和K10.3写到一个类库,所有服务放在一个类库
问题描述: 平时负责电子政务和图形调用部分,凡是牵涉到图形的都需要调用WebService服务,因此很多工程都需要添加web服务引用,现在WebForm的工程一个是10.2版本,一个是10.3版本,区 ...
- linux shell 获取进程pid
1.通过可执行程序的程序名称 a.运行程序 b.获取进程id号 c.pidof相关知识:http://www.cnblogs.com/yunsicai/p/3675938.html 2.有些程序需要在 ...
- [zt]矩阵求导公式
今天推导公式,发现居然有对矩阵的求导,狂汗--完全不会.不过还好网上有人总结了.吼吼,赶紧搬过来收藏备份. 基本公式:Y = A * X --> DY/DX = A'Y = X * A --&g ...
- Linux_系统管理命令(工作中经常使用到的)
查看网络配置信息 ifconfig 查看系统资源信息(类似win系统资源管理器) top (ps: load average 负载 Task 进程 Cpus/Mem swap 交换分区 类似wi ...
- sbt Getting org.scala-sbt sbt 0.13.12 ...
本地仓库被我搞乱了,一气之下整个删掉了本地仓库,再重启sbt卡在Getting这一步. Getting org.scala-sbt sbt 0.13.12 ... 卡住 补充sbt配置文件: 文件结构 ...
- 对ASM存储管理的一些初步理解记录
ASM:Automatic Storage Management,是ORACEL10G以后为了简化存储管理的复杂性,也是为了摆脱对其他厂商的依赖而推出的.ASM作为目前ORACLE推荐的首选存储方案, ...
- 了解C++默认编写并调用哪些函数
概念:编译器可以暗自为class创建default构造函数.copy构造函数.copy assignmengt构造函数,以及析构函数. 比如你写下:struct Node { }; 这就好像你写下这样 ...
- phpexcel的写操作将数据库中的数据导入到excel中
这个版本据说是可以支持excel2007,但是我使用2007编辑的xlsx是无法获得该库的支持.于是乎我就将它转化为2003.感觉支持地很好. 下面介绍一下具体的使用: require_once('. ...
- 使用Apache的.htaccess就可以防盗链
Apache的.htaccess可以实现很多功能,如密码保护.禁止显示目录列表.阻止/允许特定的IP地址.实现网址的301 重定向等等.本文就来说说使用Apache的.htaccess如何防盗链. 当 ...
- MVC Pager 使用
MVC Pager 4.0+ 3.0版本使用 ,直接来点使用的.一看就明白 @Ajax.Pager(Model,pagerOptions,mvcAjaxOptions); @using W ...