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
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<IEntityType, IEntityViewType>
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<IEntityType, IEntityViewType, DomainType> : IDomainModel<IEntityType, IEntityViewType>
22 where IEntityType : IEntity
23 where IEntityViewType : IEntity
24 where DomainType : IDomainModel<IEntityType, IEntityViewType>, new()
25 {
26 Protected 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<IEntityType>();
35 entityValue2 = Gateway.Create<IEntityType>();
36 }
37
38 /**//// <summary>
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 /// </summary>
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<IEntityType>(entityValue, entityValue2);
52 if (exceptColumns.Length == NBear.Common.Entity<IEntityType>.GetKeys().Length)
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<IEntityType>(keyValues.GetKeys(exceptColumns), keyValues.GetValues(exceptColumns), ID);
61 }
62 else
63 {
64 Gateway.Update<IEntityType>(keyValues.GetKeys(exceptColumns), keyValues.GetValues(exceptColumns), ID, tran);
65 }
66 }
67
68 protected virtual void DoCreate(DbTransaction tran)
69 {
70 string exceptKeyColumn = Entity<IEntityType>.GetKeys()[0];
71 if (tran == null)
72 {
73 DbTransaction t = Gateway.BeginTransaction();
74
75 try
76 {
77 Gateway.Insert<IEntityType>(entityValue, t, exceptKeyColumn);
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<IEntityType>(entityValue, tran, exceptKeyColumn);
95 LoadCreatedID(tran);
96 }
97 }
98
99 #endregion
100
101 Properties#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 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<IEntityViewType, IEntityType>(entityView);
138 entityValue2 = Gateway.ConvertEntity<IEntityViewType, IEntityType>(entityView);
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<IEntityViewType>(ID));
158 }
159
160 public static DomainType Find(object id)
161 {
162 DomainType obj = new DomainType();
163 obj.LoadFromEntity(Gateway.Get<IEntityViewType>(id));
164 return obj;
165 }
166
167 public static DomainType[] FindAll(string orderBy)
168 {
169 return EntityViewArrayToDomainArray(Gateway.SelectAll<IEntityViewType>(orderBy));
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<IEntityType>(id);
187 }
188
189 #endregion
190
191 Gateway#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<IEntityType, DomainType> : DomainModel<IEntityType, IEntityType, DomainType>
211 where IEntityType : IEntity
212 where DomainType : IDomainModel<IEntityType, IEntityType>, new()
213 {
214 }
215
216 public abstract class GuidKeyDomainModel<IEntityType, IEntityViewType, DomainType> : DomainModel<IEntityType, IEntityViewType, DomainType>
217 where IEntityType : IEntity
218 where IEntityViewType : IEntity
219 where DomainType : IDomainModel<IEntityType, IEntityViewType>, new()
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<IEntityType>(entityValue);
229 }
230 else
231 {
232 Gateway.Insert<IEntityType>(entityValue, tran);
233 }
234 }
235 }
236
237 public abstract class GuidKeyDomainModel<IEntityType, DomainType> : GuidKeyDomainModel<IEntityType, IEntityType, DomainType>
238 where IEntityType : IEntity
239 where DomainType : IDomainModel<IEntityType, IEntityType>, new()
240 {
241 }
242}
示例
首先,還是需要用NBear.Tools.EntityGen生成實體,這裡的數據庫還是采用的之前的示例Sample2中的數據庫TestRelation.mdb。
Entities.cs
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}
接著就能定義領域模型了,只需簡單的繼承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,領域模型定義完了,下面就可以方便的使用以上類了:
Usage.cs
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}