Ilungasoft Framework: 使用视图处理继承关系、Tree结构实体关系映射示例[源码]

本示例演示基于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的基本信息。

测试

好了,构建表和视图的工作至此结束,下面可以来测试一下了。

 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(nullnull)); //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"null2);  //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(nullnull)); //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(nullnull)); //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(nullnull)); //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        }

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!

posted @ 2006-04-10 11:16  Teddy's Knowledge Base  Views(3005)  Comments(0Edit  收藏  举报