从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

时间:2023-12-21 13:07:32

本来是想试着做一个简单OA项目玩玩的,真是不做不知道,一做吓死人,原来以为很简单的事情,但是做起来不是忘这就是忘那的,有的技术还得重新温习。所以还是得记录。免得哪天电脑挂了,就全没有了。

开始是看了园子里何镇汐的一系列文章,写的太好了,只看了几篇就有想写代码的冲动,很大一部分都是搬他的东西。但是我还是领误不了DDD,所以先就着三层搞搞。

我搞了两个解决方案,一个本着是想做框架,把有通用的封装了,以后要用就引dll,由于太枯燥,另一个就是想做个玩具项目,两边轮流搞搞

先是dll部分的,当然很多都没实现反正是自己的,以后再慢慢补,我这里东西很少,所以没用文件夹之类的,全部直接一个命名空间

从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

先是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试试呗,搞个三层玩玩

从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

DataModel层添加上面的DLL引用,我叫MTF指的是My Test Frame呵呵,不会英语,反正是搞的玩。

从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

安装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>

前端代码

看看效果,开始进入时,展示默认数据

从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

我这里一共有501条数据,现在默认的是每页20条,点尾页,看看一共有多少页

从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

设置每页13行

从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

点尾页看看总页数

从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

到此,我认为测试圆满结束,全部合格。但是最后我才发现数据多了一行。应该是JsonStringHelper类中的这句if (property.Name.Contains(name))有问题,属性名里包含了相同的字符串???这是我发表了之后才发现,现在太晚了,把这个改成if (property.Name==name)应该是没有问题的了。但是对这种相对硬的编码我还是有点感觉不爽。先就这样吧,太晚了。明天还在做苦力活啊,我都不是做这行的,不知道为什么 要熬夜写这些

未成品下载:http://pan.baidu.com/s/1o84Cegy