本示例演示基于
Ilungasoft Framework实现继承关系和Tree结构的实体。前面的文章已经介绍过,基于Ilungasoft Framework的开发模型使用可调试的视图(Views)代替传统ORM中不可调试的Configuration(例如:XML等各式的配置文件)。前面的Sample2已经介绍了如何使用视图处理一般的OneToMany、ManyToMany关系,本文演示的Sample4,将演示更为复杂的处理两层组织、两层权限、权限可分配给用户或组织这样的模型,包含继承和tree结构,具体演示内容包括:
1、继承映射(采用一实体一表,不冗余父表字段方式映射);
2、两种Tree结构映射方式(方式一:单表行冗余,采用用户事务维护tree关系;方式二:单表无冗余,Inner Join + Union);
3、演示Ilungasoft Framework中的一个新的用于简化处理关联实体的类OneToMany的使用。
下载
为了更好的理解示例建议先下载Sample4示例源码
基本数据表
数据表非常简单,一共六个,分别为:
1、Permission(ID,Title,ParentID)- 权限基本信息
2、User(ID,Name,Age)- 用户基本信息
3、Group(ID,Title,ParentID)- 组织基本信息
4、UserGroup(UserID,GroupID)- 用户、组织关联,该表采用单表行冗余(例如:如果添加用户到一个二层组织的纪录,则必须由用户在一个事务中添加用户到父组织的纪录的冗余行,删除是同理)方式存放数据
5、PermissionOfUser(PermissionID,UserID,Desc)- 赋给用户的权限子类,该表采用不冗余父表字段方式映射继承关系,同时采用单表无冗余(例如:如果将一个二层权限赋给用户,不需要用户添加父权限到用户的冗余纪录)方式存放数据
6、PermissionOfGroup(PermissionID,GroupID,Desc)- 赋给组织的权限子类,该表采用不冗余父表字段方式映射继承关系,同时采用单表无冗余方式存放数据
视图
本文的重点之一就在这里的视图了。
1、表UserGroup因为采用单表行冗余方式,也就意味着,正反查询直接查询该表就能获得完整的结果,只需要为了方便正反查询的同时获得User或Group的基本信息而建两个简单视图就行,这两个视图分别为:vUserInGroup和vGroupOfUser。
2、表PermissionOfUser因为采用单表无冗余方式,必须首先建立一个等价于单表行冗余的逻辑视图,视图vPermissionOfUserUnion2就是这样一个逻辑视图。他的SQL代码如下:
(select UserID, PermissionID from PermissionOfUser)
UNION (select PU.UserID, P.ID from PermissionOfUser as PU inner join Permission as P on PU.PermissionID = P.ParentID);
因为这里只演示两层的权限,如果可以有三层,则根据这个规则可以方便构造vPermissionOfUserUnion3,以此类推。
3、表PermissionOfGroup和视图vPermissionOfGroupUnion2的概念同上。
4、视图vPermissionOfGroup简单的在vPermissionOfGroupUnion2的基础上,同时获取Permission的基本信息,可以用于通过GroupID查询所有它所拥有的任意层级的权限,反向查询的的视图同理可建。
5、最后说说一类必须的查询——查询用户真正具有的权限(直接赋给用户的权限Union上用户通过所属组织被赋的权限而继承具有的权限),视图vPermissionOfUserUnionAll首先构造了这张逻辑关联表:
(SELECT UserGroup.UserID, vPermissionOfGroupUnion2.PermissionID
FROM UserGroup INNER JOIN vPermissionOfGroupUnion2 ON UserGroup.GroupID = vPermissionOfGroupUnion2.GroupID)
UNION (select UserID, PermissionID from vPermissionOfUserUnion2);
而视图vPermissionOfUser简单的为vPermissionOfUserUnionAll扩充Permission的基本信息。
测试
好了,构建表和视图的工作至此结束,下面可以来测试一下了。
Sample4是一个WinForm程序( 千万别以为Ilungasoft Framework只能用于Web开发,实际上除了Ilungaosft.Framework.Web命名空间,其他功能对WinForm程序是一样适用的,使用也是一样简单),大家可以自行运行,这里仅仅列举一下主要代码。
简单说明一下OneToMany的功能,OneToMany是一个泛型类,它接受四个泛型参数:
public class OneToMany<CreateTypeOfOne, SelectTypeOfOne, CreateTypeOfMany, SelectTypeOfMany>
where CreateTypeOfOne : IEntity
where SelectTypeOfOne : IEntity
where CreateTypeOfMany : IEntity
where SelectTypeOfMany : IEntity;
前两个参数表示One的类型,后两个表示Many的类型,CreateType表示insert/update是需要使用的实际类型,SelectType则可以是对应于Table的Entity也可以是对应于View的Entity。
现实数据库中的所有One to Many和Many to Many关系都可以由这个类来表示和简化操作。使用时,构造函数需要传入一个Many表中的外键的字段名称,并且必须先通过LoadOne函数载入One实例,否则其他函数都将不可用。
好了,本次的实例介绍就到这里,Enjoy!
1、继承映射(采用一实体一表,不冗余父表字段方式映射);
2、两种Tree结构映射方式(方式一:单表行冗余,采用用户事务维护tree关系;方式二:单表无冗余,Inner Join + Union);
3、演示Ilungasoft Framework中的一个新的用于简化处理关联实体的类OneToMany的使用。
下载
为了更好的理解示例建议先下载Sample4示例源码
基本数据表
数据表非常简单,一共六个,分别为:
1、Permission(ID,Title,ParentID)- 权限基本信息
2、User(ID,Name,Age)- 用户基本信息
3、Group(ID,Title,ParentID)- 组织基本信息
4、UserGroup(UserID,GroupID)- 用户、组织关联,该表采用单表行冗余(例如:如果添加用户到一个二层组织的纪录,则必须由用户在一个事务中添加用户到父组织的纪录的冗余行,删除是同理)方式存放数据
5、PermissionOfUser(PermissionID,UserID,Desc)- 赋给用户的权限子类,该表采用不冗余父表字段方式映射继承关系,同时采用单表无冗余(例如:如果将一个二层权限赋给用户,不需要用户添加父权限到用户的冗余纪录)方式存放数据
6、PermissionOfGroup(PermissionID,GroupID,Desc)- 赋给组织的权限子类,该表采用不冗余父表字段方式映射继承关系,同时采用单表无冗余方式存放数据
视图
本文的重点之一就在这里的视图了。
1、表UserGroup因为采用单表行冗余方式,也就意味着,正反查询直接查询该表就能获得完整的结果,只需要为了方便正反查询的同时获得User或Group的基本信息而建两个简单视图就行,这两个视图分别为:vUserInGroup和vGroupOfUser。
2、表PermissionOfUser因为采用单表无冗余方式,必须首先建立一个等价于单表行冗余的逻辑视图,视图vPermissionOfUserUnion2就是这样一个逻辑视图。他的SQL代码如下:
(select UserID, PermissionID from PermissionOfUser)
UNION (select PU.UserID, P.ID from PermissionOfUser as PU inner join Permission as P on PU.PermissionID = P.ParentID);
因为这里只演示两层的权限,如果可以有三层,则根据这个规则可以方便构造vPermissionOfUserUnion3,以此类推。
3、表PermissionOfGroup和视图vPermissionOfGroupUnion2的概念同上。
4、视图vPermissionOfGroup简单的在vPermissionOfGroupUnion2的基础上,同时获取Permission的基本信息,可以用于通过GroupID查询所有它所拥有的任意层级的权限,反向查询的的视图同理可建。
5、最后说说一类必须的查询——查询用户真正具有的权限(直接赋给用户的权限Union上用户通过所属组织被赋的权限而继承具有的权限),视图vPermissionOfUserUnionAll首先构造了这张逻辑关联表:
(SELECT UserGroup.UserID, vPermissionOfGroupUnion2.PermissionID
FROM UserGroup INNER JOIN vPermissionOfGroupUnion2 ON UserGroup.GroupID = vPermissionOfGroupUnion2.GroupID)
UNION (select UserID, PermissionID from vPermissionOfUserUnion2);
而视图vPermissionOfUser简单的为vPermissionOfUserUnionAll扩充Permission的基本信息。
测试
好了,构建表和视图的工作至此结束,下面可以来测试一下了。
1
private
void
btnLoadGroupsOfUser_Click(
object
sender, EventArgs e)
2
{
3
textBox1.Text = string.Empty;
4
OneToMany<User, User, UserGroup, vGroupOfUser> o2m = new OneToMany<User, User, UserGroup, vGroupOfUser>("UserID");
5
o2m.LoadOne("[ID] = @ID", 1);
6
textBox1.Text += SerializeHelper.Serialize(o2m.EntitySelectTypeOne) + "/r/n----/r/n";
7
textBox1.Text += SerializeHelper.SerializeArray(o2m.SelectMany(null, null)); //select all many entities
8
}
9
10
private
void
btnAddUsersToGroup_Click(
object
sender, EventArgs e)
11
{
12
textBox1.Text = string.Empty;
13
OneToMany<Group, Group, UserGroup, vUserInGroup> o2m = new OneToMany<Group, Group, UserGroup, vUserInGroup>("GroupID");
14
o2m.LoadOne("[ID] = @ID", 2);
15
16
//add user with ID 2 to loaded Group
17
vUserInGroup[] users = o2m.SelectMany("[ID] = @ID", null, 2); //no need to set the "[GroupID] = XX" where condition, because o2m auto appended this condition
18
if (users.Length == 0)
19
{
20
UserGroup newUserGroup = o2m.CreateNewEntityMany();
21
//no need to explictly set newUserGroup.GroupID, because CreateNewEntityMany() auto did this
22
newUserGroup.UserID = 2;
23
o2m.InsertMany(newUserGroup);
24
}
25
26
textBox1.Text += SerializeHelper.Serialize(o2m.EntitySelectTypeOne) + "/r/n----/r/n";
27
textBox1.Text += SerializeHelper.SerializeArray(o2m.SelectMany(null, null)); //select all many entities
28
}
29
30
private
void
btnLoadPermissionsOfUser_Click(
object
sender, EventArgs e)
31
{
32
textBox1.Text = string.Empty;
33
OneToMany<User, User, PermissionOfUser, vPermissionOfUser> o2m = new OneToMany<User, User, PermissionOfUser, vPermissionOfUser>("UserID");
34
o2m.LoadOne("[ID] = @ID", 1);
35
textBox1.Text += SerializeHelper.Serialize(o2m.EntitySelectTypeOne) + "/r/n----/r/n";
36
textBox1.Text += SerializeHelper.SerializeArray(o2m.SelectMany(null, null)); //select all many entities
37
}
38
39
private
void
btnTestAll_Click(
object
sender, EventArgs e)
40
{
41
textBox1.Text = string.Empty;
42
43
//add a new user
44
User newUser = DefaultGateway.Create<User>();
45
newUser.Name = "New User";
46
newUser.Age = 18;
47
DefaultGateway.Insert<User>(newUser, "ID");
48
49
//create a one to many object and add to group
50
OneToMany<User, User, UserGroup, vGroupOfUser> o2m = new OneToMany<User, User, UserGroup, vGroupOfUser>("UserID");
51
o2m.LoadOne("[Name] = @Name", "New User");
52
UserGroup newUserGroup = o2m.CreateNewEntityMany();
53
newUserGroup.GroupID = 1;
54
o2m.InsertMany(newUserGroup);
55
56
//create a one to many objetc and add some permissions to user
57
OneToMany<User, User, PermissionOfUser, vPermissionOfUser> o2m2 = new OneToMany<User, User, PermissionOfUser, vPermissionOfUser>("UserID");
58
o2m2.LoadOne("[ID] = @ID", o2m.EntityCreateTypeOne.ID);
59
PermissionOfUser newPou = o2m2.CreateNewEntityMany();
60
newPou.PermissionID = 8;
61
o2m2.InsertMany(newPou);
62
newPou.PermissionID = 10;
63
o2m2.InsertMany(newPou);
64
65
//display the user and permissions
66
textBox1.Text += SerializeHelper.Serialize(o2m2.EntitySelectTypeOne) + "/r/n----/r/n";
67
textBox1.Text += SerializeHelper.SerializeArray(o2m2.SelectMany(null, null)); //select all many entities
68
69
//delete the added user and all the groups and permissions
70
DbTransaction tran = DefaultGateway.BeginTransaction();
71
72
try
73
{
74
o2m.DeleteMany(null, tran);
75
o2m2.DeleteOne(true, tran);
76
77
tran.Commit();
78
}
79
catch
80
{
81
tran.Rollback();
82
throw;
83
}
84
finally
85
{
86
DefaultGateway.CloseTransaction(tran);
87
}
88
}

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

Sample4是一个WinForm程序( 千万别以为Ilungasoft Framework只能用于Web开发,实际上除了Ilungaosft.Framework.Web命名空间,其他功能对WinForm程序是一样适用的,使用也是一样简单),大家可以自行运行,这里仅仅列举一下主要代码。
简单说明一下OneToMany的功能,OneToMany是一个泛型类,它接受四个泛型参数:
public class OneToMany<CreateTypeOfOne, SelectTypeOfOne, CreateTypeOfMany, SelectTypeOfMany>
where CreateTypeOfOne : IEntity
where SelectTypeOfOne : IEntity
where CreateTypeOfMany : IEntity
where SelectTypeOfMany : IEntity;
前两个参数表示One的类型,后两个表示Many的类型,CreateType表示insert/update是需要使用的实际类型,SelectType则可以是对应于Table的Entity也可以是对应于View的Entity。
现实数据库中的所有One to Many和Many to Many关系都可以由这个类来表示和简化操作。使用时,构造函数需要传入一个Many表中的外键的字段名称,并且必须先通过LoadOne函数载入One实例,否则其他函数都将不可用。
好了,本次的实例介绍就到这里,Enjoy!