从头开始一步一步实现EF6+Autofac+MVC5+Bootstarp极简的实现前后台ajax表格展示及分页实现的相关介绍,具体实例请看下文
本来是想试着做一个简单OA项目玩玩的,真是不做不知道,一做吓死人,原来以为很简单的事情,但是做起来不是忘这就是忘那的,有的技术还得重新温习。所以还是得记录。免得哪天电脑挂了,就全没有了。
开始是看了园子里何镇汐的一系列文章,写的太好了,只看了几篇就有想写代码的冲动,很大一部分都是搬他的东西。但是我还是领误不了DDD,所以先就着三层搞搞。
我搞了两个解决方案,一个本着是想做框架,把有通用的封装了,以后要用就引dll,由于太枯燥,另一个就是想做个玩具项目,两边轮流搞搞
先是dll部分的,当然很多都没实现反正是自己的,以后再慢慢补,我这里东西很少,所以没用文件夹之类的,全部直接一个命名空间
先是autofac封装类,只是简单封装了一下,做玩具够用,跟上一篇博客一样的,这里不说了
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 的设计是参考何兄的,大家可以去看他的文章,写的太好了,这里几乎是搬的
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只搞了一个方法,以后再搞
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
1
2
3
4
5
6
7
8
9
|
using
System;
namespace
MTF.Domain
{
public
interface IUnitOfWork:IDisposable
{
void
Commit();
}
}
|
View 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
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层
简单的工作单元
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数据操作,还是以后慢慢再搞
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的,但是想着以后别的地方可能会用到,所以还是公共了
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就可以使用它的,它们共用一个工作单元
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试试呗,搞个三层玩玩
DataModel层添加上面的DLL引用,我叫MTF指的是My Test Frame呵呵,不会英语,反正是搞的玩。
安装EF和AUTOFAC包开搞,先搞个BaseEntity,由于我int 类型不会初始化的时候赋值,
但是又不想GUID来排序,所以我想的办法是实体接口的时候,给的GId的属性名,主键我还是用的int类型,Guid初始化的时候赋值,它同样是唯一的,方便内存操作,int类型做自增的主键,在插入数据库后才有值。
做了三个类,用户,权限和角色,还有三个中间类,以配多对多关系,本着学习的精神,我用的CodeFirst和F..Api(不会定这个单词了,晕)方式配置映射
一样的简单玩玩的,可能还没有注释,直接上了
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
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
配置映射
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
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
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
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
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
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
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
数据库上下文,也可以说是工作单元
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层和安装相关的包,代码很少,就几个空类,主要是继承了父类
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()方法,也就是程序开处,注入必要的依赖,贯穿整个生命周期
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层在
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());
}
}
}
|
控制器代码
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不是很熟,作了注释的
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=
"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)应该是没有问题的了。