?NBear是Teddy开发的快速开发框架,在之前的5个示例中,主要演示了主要的框架功能和业务领域模型不太复杂情形下忽略领域层的应用范例。
但是,当业务模型相对复杂,单纯基于简单实体的强类型数据访问接口,可能就会使得太多的业务逻辑被分散到service或facade层,此时,我们就最好加一层独立的业务领域模型层来封装实体和强类型接口的使用。本文为您演示基于NBear v1.6.0中新增的NBear.Domain的领域模型设计示例。
??? NBear.Domain
??? NBear.Domain主要为您提供了基类DomainModel和GuidKeyDomainModel,前者用于采用自增长ID主键的实体,后者用于采用Guid主键的实体。只需将他们作为你的领域类的基类,它就能提供最基本的领域类需要的CRUD等功能(包括Save, Delete, Find, FindAll等),您可以方便的以此为基础进行扩展。
??? DomainModel.cs
...#region
1using System;
2using System.Data;
3using System.Data.Common;
4using System.Collections.Generic;
5using System.Text;
6using NBear.Common;
7using NBear.Data;
8
9namespace NBear.Domain
10...{
11 public interface IDomainModel
12 where IEntityType : IEntity
13 where IEntityViewType : IEntity
14 ...{
15 void Save();
16 void Save(DbTransaction tran);
17 void LoadFromEntity(IEntityViewType entity);
18 object ID ...{ get; }
19 }
20
21 public abstract class DomainModel
22 where IEntityType : IEntity
23 where IEntityViewType : IEntity
24 where DomainType : IDomainModel
25 ...{
26 Protected MembersProtected Members#region Protected Members
27
28 protected IEntityType entityValue;
29 protected IEntityType entityValue2;
30 protected IEntityViewType entityViewValue;
31
32 protected DomainModel()
33 ...{
34 entityValue = Gateway.Create
35 entityValue2 = Gateway.Create
36 }
37
38 /**//**//**////
39 /**//// override this method in sub class to customly load auto-created key column id if neccessary
40 /**//// by default, when saving a new domain model, the latest auto created ID will be loaded.
41 /**////
42 protected virtual void LoadCreatedID(DbTransaction tran)
43 ...{
44 KeyValueCollection keyValues = entityValue.GetKeyValues();
45
46 keyValues[0] = Gateway.Db.ExecuteScalar(tran, CommandType.Text, string.Format("select max([{0}]) from [{1}]", keyValues.GetKeys()[0], typeof(IEntityType).Name));
47 }
48
49 protected virtual void DoUpdate(DbTransaction tran)
50 ...{
51 string[] exceptColumns = Gateway.CompareEntities
52 if (exceptColumns.Length == NBear.Common.Entity
53 ...{
54 //no columns are modified, so no need to update
55 return;
56 }
57 KeyValueCollection keyValues = entityValue.GetKeyValues();
58 if (tran == null)
59 ...{
60 Gateway.Update
61 }
62 else
63 ...{
64 Gateway.Update
65 }
66 }
67
68 protected virtual void DoCreate(DbTransaction tran)
69 ...{
70 string exceptKeyColumn = Entity
71 if (tran == null)
72 ...{
73 DbTransaction t = Gateway.BeginTransaction();
74
75 try
76 ...{
77 Gateway.Insert
78
79 LoadCreatedID(t);
80
81 t.Commit();
82 }
83 catch
84 ...{
85 t.Rollback();
86 }
87 finally
88 ...{
89 Gateway.CloseTransaction(t);
90 }
91 }
92 else
93 ...{
94 Gateway.Insert
95 LoadCreatedID(tran);
96 }
97 }
98
99 #endregion
100
101 PropertiesProperties#region Properties
102
103 public IEntityType EntityValue
104 ...{
105 get
106 ...{
107 return entityValue;
108 }
109 }
110
111 public IEntityViewType EntityViewValue
112 ...{
113 get
114 ...{
115 return entityViewValue;
116 }
117 }
118
119 public virtual object ID
120 ...{
121 get
122 ...{
123 return entityValue.GetKeyValues()[0];
124 }
125 }
126
127 #endregion
128
129 Basic CRUDBasic CRUD#region Basic CRUD
130
131 public virtual void LoadFromEntity(IEntityViewType entityView)
132 ...{
133 if (entityView == null)
134 ...{
135 return;
136 }
137 entityValue = Gateway.ConvertEntity
138 entityValue2 = Gateway.ConvertEntity
139 }
140
141 public void Save()
142 ...{
143 Save(null);
144 }
145
146 public virtual void Save(DbTransaction tran)
147 ...{
148 if (ID == null || Convert.ToInt32(ID) == 0)
149 ...{
150 DoCreate(tran);
151 }
152 else
153 ...{
154 DoUpdate(tran);
155 }
156
157 LoadFromEntity(Gateway.Get
158 }
159
160 public static DomainType Find(object id)
161 ...{
162 DomainType obj = new DomainType();
163 obj.LoadFromEntity(Gateway.Get
164 return obj;
165 }
166
167 public static DomainType[] FindAll(string orderBy)
168 ...{
169 return EntityViewArrayToDomainArray(Gateway.SelectAll
170 }
171
172 public static DomainType[] EntityViewArrayToDomainArray(IEntityViewType[] entityViews)
173 ...{
174 DomainType[] objs = new DomainType[entityViews.Length];
175 for (int i = 0; i < objs.Length; i++)
176 ...{
177 DomainType obj = new DomainType();
178 obj.LoadFromEntity(entityViews[i]);
179 objs[i] = obj;
180 }
181 return objs;
182 }
183
184 public static void Delete(object id)
185 ...{
186 Gateway.Delete
187 }
188
189 #endregion
190
191 GatewayGateway#region Gateway
192
193 private static NBear.Data.Facade.Gateway _Gateway = null;
194
195 public static NBear.Data.Facade.Gateway Gateway
196 ...{
197 get
198 ...{
199 return (_Gateway == null ? GatewayManager.DefaultGateway : _Gateway);
200 }
201 set
202 ...{
203 _Gateway = value;
204 }
205 }
206
207 #endregion
208 }
209
210 public abstract class DomainModel
211 where IEntityType : IEntity
212 where DomainType : IDomainModel
213 ...{
214 }
215
216 public abstract class GuidKeyDomainModel
217 where IEntityType : IEntity
218 where IEntityViewType : IEntity
219 where DomainType : IDomainModel
220 ...{
221 protected override void DoCreate(DbTransaction tran)
222 ...{
223 //create guid
224 entityValue.GetKeyValues()[0] = Guid.NewGuid().ToString();
225
226 if (tran == null)
227 ...{
228 Gateway.Insert
229 }
230 else
231 ...{
232 Gateway.Insert
233 }
234 }
235 }
236
237 public abstract class GuidKeyDomainModel
238 where IEntityType : IEntity
239 where DomainType : IDomainModel
240 ...{
241 }
242}
#endregion
示例
首先,还是需要用NBear.Tools.EntityGen生成实体,这里的数据库还是采用的之前的示例Sample2中的数据库TestRelation.mdb。
Entities.cs
...#region
1using System;
2using System.Collections.Generic;
3using System.Text;
4using NBear.Common;
5
6namespace Sample6.Entities
7...{
8 public interface Group : IEntity
9 ...{
10 int ID ...{ get; set; }
11 string Title ...{ get; set; }
12 string Description ...{ get; set; }
13 System.DateTime CreateTime ...{ get; set; }
14 int ParentID ...{ get; set; }
15 }
16
17 public interface Message : IEntity
18 ...{
19 int ID ...{ get; set; }
20 int FromUserID ...{ get; set; }
21 int ToUserID ...{ get; set; }
22 string Title ...{ get; set; }
23 string Content ...{ get; set; }
24 System.DateTime SendTime ...{ get; set; }
25 }
26
27 public interface User : IEntity
28 ...{
29 int ID ...{ get; set; }
30 string Name ...{ get; set; }
31 bool Gender ...{ get; set; }
32 double Salary ...{ get; set; }
33 }
34
35 public interface UserGroup : IEntity
36 ...{
37 int UserID ...{ get; set; }
38 int GroupID ...{ get; set; }
39 }
40
41 public interface vGroup : IEntity
42 ...{
43 int ID ...{ get; set; }
44 string Title ...{ get; set; }
45 string Description ...{ get; set; }
46 System.DateTime CreateTime ...{ get; set; }
47 int ParentID ...{ get; set; }
48 int UserID ...{ get; set; }
49 }
50
51 public interface vMessage : IEntity
52 ...{
53 int ID ...{ get; set; }
54 int FromUserID ...{ get; set; }
55 string FromUserName ...{ get; set; }
56 int ToUserID ...{ get; set; }
57 string ToUserName ...{ get; set; }
58 string Title ...{ get; set; }
59 string Content ...{ get; set; }
60 System.DateTime SendTime ...{ get; set; }
61 }
62
63 public interface vUser : IEntity
64 ...{
65 int ID ...{ get; set; }
66 string Name ...{ get; set; }
67 bool Gender ...{ get; set; }
68 double Salary ...{ get; set; }
69 int GroupID ...{ get; set; }
70 }
71}
#endregion
推介网络内容 :http://www.vlan9.com
接着就能定义领域模型了,只需简单的继承DomainModel,你的类就拥有了基本的CURD接口,如下面的Message类,你也可以扩展你的类,为你的领域类扩充复杂的领域功能,使用OneToMany类,操作与当前类关联的其他实体也非常便利,如这里的Group和User类。
Domains.cs
1using System;
2using System.Collections.Generic;
3using System.Text;
4using NBear.Common;
5using NBear.Data.Facade;
6using NBear.Domain;
7
8namespace Sample6.Domains
9{
10 public class Group : DomainModel<Entities.Group, Entities.vGroup, Group>
11 {
12 private OneToMany<Entities.Group, Entities.vGroup, Entities.UserGroup, Entities.vUser> groupToUsers;
13
14 public override void LoadFromEntity(Sample6.Entities.vGroup entityView)
15 {
16 base.LoadFromEntity(entityView);
17
18 groupToUsers = new OneToMany<Entities.Group,Entities.vGroup,Entities.UserGroup,Entities.vUser>(Gateway.Db, "GroupID", entityValue, entityView);
19 }
20
21 public User[] FindUsersInGroup(string orderBy)
22 {
23 return (groupToUsers == null ? null : User.EntityViewArrayToDomainArray(groupToUsers.SelectMany(null, orderBy)));
24 }
25
26 public void AddUserToGroup(object userID)
27 {
28 if (groupToUsers == null)
29 {
30 return;
31 }
32
33 Entities.UserGroup userGroup = groupToUsers.CreateNewRelationEntity();
34 userGroup.UserID = (int)userID;
35 groupToUsers.InsertMany(userGroup);
36 }
37
38 public void DeleteUserFromGroup(object userID)
39 {
40 if (groupToUsers == null)
41 {
42 return;
43 }
44
45 groupToUsers.DeleteMany("[UserID] = @UserID", userID);
46 }
47 }
48
49 public class Message : DomainModel<Entities.Message, Entities.vMessage, Message>
50 {
51 }
52
53 public class User : DomainModel<Entities.User, Entities.vUser, User>
54 {
55 private OneToMany<Entities.User, Entities.vUser, Entities.Message, Entities.vMessage> fromUserToMessages;
56 private OneToMany<Entities.User, Entities.vUser, Entities.Message, Entities.vMessage> toUserToMessages;
57
58 public override void LoadFromEntity(Sample6.Entities.vUser entityView)
59 {
60 base.LoadFromEntity(entityView);
61
62 fromUserToMessages = new OneToMany<Entities.User, Entities.vUser, Entities.Message, Entities.vMessage>(Gateway.Db, "fromUserID", entityValue, entityView);
63 toUserToMessages = new OneToMany<Entities.User, Entities.vUser, Entities.Message, Entities.vMessage>(Gateway.Db, "toUserID", entityValue, entityView);
64 }
65
66 public Message[] FindSentMessages(string orderBy)
67 {
68 if (fromUserToMessages == null)
69 {
70 return null;
71 }
72
73 return Message.EntityViewArrayToDomainArray(fromUserToMessages.SelectMany(null, orderBy));
74 }
75
76 public Message[] FindReceivedMessages(string orderBy)
77 {
78 if (toUserToMessages == null)
79 {
80 return null;
81 }
82
83 return Message.EntityViewArrayToDomainArray(toUserToMessages.SelectMany(null, orderBy));
84 }
85 }
86}
ok,领域模型定义完了,下面就可以方便的使用以上类了:
1using System;
2using System.Collections.Generic;
3using System.Data.Common;
4using System.Text;
5using NBear.Domain;
6using Sample6.Domains;
7using NBear.Data.Facade;
8
9namespace Sample6
10{
11 public class Usage
12 {
13 public static void Main()
14 {
15 //first you should set GatewayManager.DefaultGateway for all Domain Models before using them
16 GatewayManager.DefaultGateway = new Gateway(DatabaseType.MsAccess, @"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\Teddy\NBear\dist\Sample6\App_Data\TestRelation.mdb");
17
18 //if neccessary, you can set Specific Domain Models using specific Gateway instead of DefaultGateway
19 //Group.Gateway = ;
20 //Message.Gateway = ;
21 //User.Gateway = ;
22
23 //use Domain Models
24
25 //find group & users in group
26 Group group = Group.Find(1);
27 User[] usersInGroup = group.FindUsersInGroup("ID desc");
28
29 //modify and save group
30 //only modified properties will be in the update SQL which will be created behind domain model code
31 group.EntityValue.Description = "modified description";
32 group.Save();
33
34 //find user & delete from group
35 User user = usersInGroup[0];
36 Message[] sentMessages = user.FindSentMessages("SendTime desc");
37 group.DeleteUserFromGroup(user.ID);
38
39 //create new user & add to group
40 User newUser = new User();
41 newUser.EntityValue.Name = "new user";
42 newUser.EntityValue.Salary = 1000;
43 newUser.EntityValue.Gender = false;
44 newUser.Save();
45 group.AddUserToGroup(newUser.ID);
46
47 //modify user salary, save & send message in a transaction
48 DbTransaction tran = User.Gateway.BeginTransaction();
49 try
50 {
51 user.EntityValue.Salary = 99999;
52 user.Save(tran);
53
54 Message msg = new Message();
55 msg.EntityValue.Title = "new msg";
56 msg.EntityValue.Content = "salary changed";
57 msg.EntityValue.FromUserID = user.EntityValue.ID;
58 msg.EntityValue.ToUserID = 3;
59 msg.EntityValue.SendTime = DateTime.Now;
60 msg.Save(tran);
61
62 tran.Commit();
63 }
64 catch
65 {
66 tran.Rollback();
67 throw;
68 }
69 finally
70 {
71 User.Gateway.CloseTransaction(tran);
72 }
73
74 //if you want to access more user's value than its basic value, you can access user.EntityViewType, which is its view entity - vUser
75 int groupIDOfUser = user.EntityViewValue.GroupID;
76 }
77 }
78 }