基于NBear的Domain层设计
NBear是Teddy开发的快速开发框架,在之前的5个示例中,主要演示了主要的框架功能和业务领域模型不太复杂情形下忽略领域层的应用范例。但是,当业务模型相对复杂,单纯基于简单实体的强类型数据访问接口,可能就会使得太多的业务逻辑被分散到service或facade层,此时,我们就最好加一层独立的业务领域模型层来封装实体和强类型接口的使用。本文为您演示基于NBear v1.6.0中新增的NBear.Domain的领域模型设计示例。
NBear是Teddy开发的快速开发框架,在之前的5个示例中,主要演示了主要的框架功能和业务领域模型不太复杂情形下忽略领域层的应用范例。但是,当业务模型相对复杂,单纯基于简单实体的强类型数据访问接口,可能就会使得太多的业务逻辑被分散到service或facade层,此时,我们就最好加一层独立的业务领域模型层来封装实体和强类型接口的使用。本文为您演示基于NBear v1.6.0中新增的NBear.Domain的领域模型设计示例。
下载源码及示例
您可以从这里下载NBear最新版本及Sample6源码
NBear.Domain
NBear.Domain主要为您提供了基类DomainModel和GuidKeyDomainModel,前者用于采用自增长ID主键的实体,后者用于采用Guid主键的实体。只需将他们作为你的领域类的基类,它就能提供最基本的领域类需要的CRUD等功能(包括Save, Delete, Find, FindAll等),您可以方便的以此为基础进行扩展。
1
using System;2
using System.Data;3
using System.Data.Common;4
using System.Collections.Generic;5
using System.Text;6
using NBear.Common;7
using NBear.Data;8

9
namespace NBear.Domain10


{11
public interface IDomainModel<IEntityType, IEntityViewType>12
where IEntityType : IEntity13
where IEntityViewType : IEntity14

{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 : IEntity23
where IEntityViewType : IEntity24
where DomainType : IDomainModel<IEntityType, IEntityViewType>, new()25

{26

Protected Members#region Protected Members27

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 neccessary40
/// 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 update55
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
else63

{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
try76

{77
Gateway.Insert<IEntityType>(entityValue, t, exceptKeyColumn);78

79
LoadCreatedID(t);80

81
t.Commit();82
}83
catch84

{85
t.Rollback();86
}87
finally88

{89
Gateway.CloseTransaction(t);90
}91
}92
else93

{94
Gateway.Insert<IEntityType>(entityValue, tran, exceptKeyColumn);95
LoadCreatedID(tran);96
}97
}98

99
#endregion100

101

Properties#region Properties102

103
public IEntityType EntityValue104

{105
get106

{107
return entityValue;108
} 109
}110

111
public IEntityViewType EntityViewValue112

{113
get114

{115
return entityViewValue;116
}117
}118

119
public virtual object ID120

{121
get122

{123
return entityValue.GetKeyValues()[0];124
}125
}126

127
#endregion128

129

Basic CRUD#region Basic CRUD130

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
else153

{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
#endregion190

191

Gateway#region Gateway192

193
private static NBear.Data.Facade.Gateway _Gateway = null;194

195
public static NBear.Data.Facade.Gateway Gateway196

{197
get198

{199
return (_Gateway == null ? GatewayManager.DefaultGateway : _Gateway);200
}201
set202

{203
_Gateway = value;204
}205
}206

207
#endregion208
}209

210
public abstract class DomainModel<IEntityType, DomainType> : DomainModel<IEntityType, IEntityType, DomainType>211
where IEntityType : IEntity212
where DomainType : IDomainModel<IEntityType, IEntityType>, new()213

{214
}215

216
public abstract class GuidKeyDomainModel<IEntityType, IEntityViewType, DomainType> : DomainModel<IEntityType, IEntityViewType, DomainType>217
where IEntityType : IEntity218
where IEntityViewType : IEntity219
where DomainType : IDomainModel<IEntityType, IEntityViewType>, new()220

{221
protected override void DoCreate(DbTransaction tran)222

{223
//create guid224
entityValue.GetKeyValues()[0] = Guid.NewGuid().ToString();225

226
if (tran == null)227

{228
Gateway.Insert<IEntityType>(entityValue);229
}230
else231

{232
Gateway.Insert<IEntityType>(entityValue, tran);233
}234
}235
}236

237
public abstract class GuidKeyDomainModel<IEntityType, DomainType> : GuidKeyDomainModel<IEntityType, IEntityType, DomainType>238
where IEntityType : IEntity239
where DomainType : IDomainModel<IEntityType, IEntityType>, new()240

{241
}242
}示例
首先,还是需要用NBear.Tools.EntityGen生成实体,这里的数据库还是采用的之前的示例Sample2中的数据库TestRelation.mdb。
1
using System;2
using System.Collections.Generic;3
using System.Text;4
using NBear.Common;5

6
namespace Sample6.Entities7


{8
public interface Group : IEntity9

{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 : IEntity18

{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 : IEntity28

{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 : IEntity36

{37

int UserID
{ get; set; }38

int GroupID
{ get; set; }39
}40

41
public interface vGroup : IEntity42

{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 : IEntity52

{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 : IEntity64

{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类。
1
using System;2
using System.Collections.Generic;3
using System.Text;4
using NBear.Common;5
using NBear.Data.Facade;6
using NBear.Domain;7

8
namespace Sample6.Domains9


{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,领域模型定义完了,下面就可以方便的使用以上类了:
1
using System;2
using System.Collections.Generic;3
using System.Data.Common;4
using System.Text;5
using NBear.Domain;6
using Sample6.Domains;7
using NBear.Data.Facade;8

9
namespace Sample610


{11
public class Usage12

{13
public static void Main()14

{15
//first you should set GatewayManager.DefaultGateway for all Domain Models before using them16
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 DefaultGateway19
//Group.Gateway =
;20
//Message.Gateway =
;21
//User.Gateway =
;22

23
//use Domain Models24

25
//find group & users in group26
Group group = Group.Find(1);27
User[] usersInGroup = group.FindUsersInGroup("ID desc");28

29
//modify and save group30
//only modified properties will be in the update SQL which will be created behind domain model code31
group.EntityValue.Description = "modified description";32
group.Save();33

34
//find user & delete from group35
User user = usersInGroup[0];36
Message[] sentMessages = user.FindSentMessages("SendTime desc");37
group.DeleteUserFromGroup(user.ID);38

39
//create new user & add to group40
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 transaction48
DbTransaction tran = User.Gateway.BeginTransaction();49
try50

{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
catch65

{66
tran.Rollback();67
throw;68
}69
finally70

{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 - vUser75
int groupIDOfUser = user.EntityViewValue.GroupID;76
}77
}78
}

浙公网安备 33010602011771号