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

 从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现的相关介绍,具体实例请看下文

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

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

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

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

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

先是autofac封装类,只是简单封装了一下,做玩具够用,跟上一篇博客一样的,这里不说了

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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 的设计是参考何兄的,大家可以去看他的文章,写的太好了,这里几乎是搬的

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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
 
    }
}

View Code

Repository数据操作接口,这里也是搬的,但有一点不一样,考虑到排序我不想用Guid类型的,所以没有约束Entity必须实现IBaseEntity接口或者聚合根,因为我用的三层,没用聚合根,再者我在后面的Service层想用到分页排序,看到后面应该就能理解的。但是我并不知道这样对不对

IUnitOfWork只搞了一个方法,以后再搞

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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);
        
    }
}

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

code
1
2
3
4
5
6
7
8
9
using System;
 
namespace MTF.Domain
{
    public interface IUnitOfWork:IDisposable
    {
        void Commit();
    }
}

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

code
1
2
3
4
5
6
7
8
9
10
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
 
namespace MTF.Domain
{
    public interface IValidationHandler
    {
        void Handle(ICollection<ValidationResult> validationResults);
    }
}

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

code
1
2
3
4
5
6
7
8
9
using System.ComponentModel.DataAnnotations;
 
namespace MTF.Domain
{
    public interface IValidationRule
    {
        ValidationResult Validate();
    }
}

View Code

Domain现在只完成了这么多,其它的接口还没搞,还是以后再搞,懒的。

后面是EF部分了,引用Domain层

简单的工作单元

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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数据操作,还是以后慢慢再搞

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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的,但是想着以后别的地方可能会用到,所以还是公共了

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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

直接给代码先,都是很简单,不知道合不合理,这里用到了Pager类,当作属性使用,客户端得到Service就可以使用它的,它们共用一个工作单元

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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(不会定这个单词了,晕)方式配置映射

一样的简单玩玩的,可能还没有注释,直接上了

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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

配置映射

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

code
1
2
3
4
5
6
7
8
9
10
11
12
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 从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

code
1
2
3
4
5
6
7
8
9
10
11
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 从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现

code
1
2
3
4
5
6
7
8
9
10
11
12
13
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);
        }
    }
}

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

code
1
2
3
4
5
6
7
8
9
10
11
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);
        }
    }
}

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

code
1
2
3
4
5
6
7
8
9
10
11
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);
        }
    }
}

PermissionMap

数据库上下文,也可以说是工作单元

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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层和安装相关的包,代码很少,就几个空类,主要是继承了父类

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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()方法,也就是程序开处,注入必要的依赖,贯穿整个生命周期

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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层在

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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());
        }
 
    }
}

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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不是很熟,作了注释的

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

code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
@{
    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="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)应该是没有问题的了。

原文地址:https://www.cnblogs.com/zxh1919/p/7873839.html