c#领域驱动设计
代码是个程序员都能写,
怎么的代码才是好的,
--------------------------------------------------------------------------------------------------
1.设计
1.可靠性和可得性
数据库有问题的时候,一般都是系统重启,新系统数据系统应该能够在使用过程中备份,而不应该轻易发生错误。
2.伸缩性
系统应该能够处理用户源源不断的需求。
3.可维护性
系统代码重复改一个需求到处粘贴复制,这种情况下必须考虑重构,领域逻辑处于核心位置,而且绝对不重复,可复用。
2.设计架构层
1.基础设施层
该层被所有的层所引用,定义所有的基础设施所需的方法。
2.应用层
主要维护任务的状态,负责不同领域对象之间的协调动作,该层的方法大多都是静态的
3.领域层
该层主要负责业务逻辑
4.持久层
该层主要负责数据持久化(与数据库打交到)
5.UI层
页面呈现
6.数据传输层
数据实体对象(负责数据运输的实体对象)
基础设施层
1. 定义一个实体接口 IEntity
定义一个实体接口标识该对象为实体对象(并且标识主键key)
1 /// <summary> 2 /// 实体接口 3 /// </summary> 4 public interface IEntity 5 { 6 /// <summary> 7 /// key 8 /// </summary> 9 object Key { get; } 10 }
2.抽象一个分层超类型 EntityBase
抽象一个基类所有的领域模型都将继承它以获得他们的标识
1 /// <summary> 2 /// 实体抽象类 3 /// </summary> 4 public abstract class EntityBase : IEntity 5 { 6 /// <summary> 7 /// 标识key 8 /// </summary> 9 private readonly object key; 10 11 /// <summary> 12 /// Initializes a new instance of the <see cref="EntityBase"/> class. 13 /// 默认构造函数 default constructor 14 /// </summary> 15 protected EntityBase() 16 : this(null) 17 { 18 } 19 20 /// <summary> 21 /// Initializes a new instance of the <see cref="EntityBase"/> class. 22 /// </summary> 23 /// <param name="key">key</param> 24 protected EntityBase(object key) 25 { 26 this.key = key; 27 } 28 29 /// <summary> 30 /// Gets the key. 31 /// </summary> 32 public object Key 33 { 34 get 35 { 36 return this.key; 37 } 38 } 39 40 /// <summary> 41 /// The equals. 42 /// </summary> 43 /// <param name="other"> 44 /// The other. 45 /// </param> 46 /// <returns> 47 /// The <see cref="bool"/>. 48 /// </returns> 49 protected bool Equals(EntityBase other) 50 { 51 return Equals(this.Key, other.Key); 52 } 53 54 /// <summary> 55 /// The equals. 56 /// </summary> 57 /// <param name="entity"> 58 /// The entity. 59 /// </param> 60 /// <returns> 61 /// The <see cref="bool"/>. 62 /// </returns> 63 public override bool Equals(object entity) 64 { 65 if (entity == null || !(entity is EntityBase)) 66 { 67 return false; 68 } 69 70 return this == (EntityBase)entity; 71 } 72 73 /// <summary> 74 /// The get hash code. 75 /// </summary> 76 /// <returns> 77 /// The <see cref="int"/>. 78 /// </returns> 79 public override int GetHashCode() 80 { 81 return this.Key != null ? this.Key.GetHashCode() : 0; 82 } 83 84 /// <summary> 85 /// The ==. 86 /// </summary> 87 /// <param name="left"> 88 /// The base 1. 89 /// </param> 90 /// <param name="right"> 91 /// The base 2. 92 /// </param> 93 /// <returns> 94 /// </returns> 95 public static bool operator ==(EntityBase left, EntityBase right) 96 { 97 if ((object)left == null && (object)right == null) 98 { 99 return true; 100 } 101 102 if ((object)left == null || (object)right == null) 103 { 104 return false; 105 } 106 107 return left.Key == right.Key; 108 } 109 110 /// <summary> 111 /// The !=. 112 /// </summary> 113 /// <param name="left"> 114 /// The base 1. 115 /// </param> 116 /// <param name="right"> 117 /// The base 2. 118 /// </param> 119 /// <returns> 120 /// </returns> 121 public static bool operator !=(EntityBase left, EntityBase right) 122 { 123 return !(left == right); 124 } 125 }
做一个泛型的标识继承EntityBase
1 /// <summary> 2 /// The entity. 3 /// </summary> 4 /// <typeparam name="T"> 5 /// </typeparam> 6 public abstract class EntityBase<T> : EntityBase 7 { 8 /// <summary> 9 /// Initializes a new instance of the <see cref="EntityBase{T}"/> class. 10 /// Initializes a new instance of the <see cref="EntityBase"/> class. 11 /// 默认构造函数 default constructor 12 /// </summary> 13 protected EntityBase() 14 : base(null) 15 { 16 } 17 18 /// <summary> 19 /// Initializes a new instance of the <see cref="EntityBase{T}"/> class. 20 /// Initializes a new instance of the <see cref="EntityBase"/> class. 21 /// </summary> 22 /// <param name="key"> 23 /// key 24 /// </param> 25 protected EntityBase(T key) 26 : base(key) 27 { 28 } 29 30 /// <summary> 31 /// Gets the key. 32 /// </summary> 33 public new T Key 34 { 35 get 36 { 37 T @default = default(T); 38 if (base.Key == null) 39 { 40 return @default; 41 } 42 43 return (T)base.Key; 44 } 45 } 46 }
3. 仓储接口 IRepository<in TKey, TValue>
仓储接口提供增删查改的方法签名,并且多了一个索引 TValue类型并且标识为IEntity
1 /// <summary> 2 /// 仓储接口 3 /// </summary> 4 /// <typeparam name="TKey">TKey</typeparam> 5 /// <typeparam name="TValue">TValue</typeparam> 6 public interface IRepository<in TKey, TValue> 7 where TValue : EntityBase<TKey> 8 { 9 /// <summary> 10 /// 根据key查询 11 /// </summary> 12 /// <param name="key">key</param> 13 /// <returns>TValue</returns> 14 TValue FindBy(TKey key); 15 16 /// <summary> 17 /// 添加 18 /// </summary> 19 /// <param name="item">item</param> 20 void Add(TValue item); 21 22 /// <summary> 23 /// 索引查询 24 /// </summary> 25 /// <param name="key">key</param> 26 /// <returns>TValue</returns> 27 TValue this[TKey key] { get; set; } 28 29 /// <summary> 30 /// 删除 31 /// </summary> 32 /// <param name="item">item</param> 33 void Remove(TValue item); 34 35 /// <summary> 36 /// 更新 37 /// </summary> 38 /// <param name="item">item</param> 39 void Update(TValue item); 40 }
4.仓储工厂
通过配置文件创建仓储(配置类就不多说,稍后附上源码),为了决定创建哪一种仓储,RespositoryFactory类使用泛型类型参数。
1 /// <summary> 2 /// 仓储工厂 3 /// </summary> 4 public static class RepositoryFactory 5 { 6 /// <summary> 7 /// Dictionary to enforce the singleton pattern 8 /// </summary> 9 private static readonly Dictionary<string, object> m_respository = new Dictionary<string, object>(); 10 11 /// <summary> 12 /// The get repository. 13 /// </summary> 14 /// <typeparam name="TRepository"> 15 /// </typeparam> 16 /// <typeparam name="TEntity"> 17 /// </typeparam> 18 /// <returns> 19 /// The <see cref="TRepository"/>. 20 /// </returns> 21 public static TRepository GetRepository<TRepository, TEntity>() 22 where TRepository : class, IRepository<TEntity> 23 where TEntity : EntityBase 24 { 25 TRepository respository = default(TRepository); 26 string interfaceShortName = typeof(TRepository).Name; 27 if (!m_respository.ContainsKey(interfaceShortName)) 28 { 29 RepositorySettings settings = (RepositorySettings)ConfigurationManager.GetSection(RepositoryMappingConstants.RepositoryMappingsConfigurationSectionName); 30 string repositoryFullTypeName = settings.RepositoryMappings[interfaceShortName].RepositoryFullTypeName; 31 Type type = Type.GetType(repositoryFullTypeName); 32 if (type != null) 33 { 34 respository = Activator.CreateInstance(type) as TRepository; 35 m_respository.Add(interfaceShortName, respository); 36 } 37 } 38 else 39 { 40 respository = (TRepository)m_respository[interfaceShortName]; 41 } 42 43 return respository; 44 } 45 }
5.工作单元
由于需要同时操作几个仓储(同时更新订单状态,订单详细信息)要求操作结果一致。
调用折注册---对象的用户必须记得注册到工作单元
对象注册-----对象把自身注册到工作单元
工作单元仓储接口
主要定义仓储的3个基本操作签名
1 /// <summary> 2 /// 工作单元仓储接口 3 /// </summary> 4 public interface IUnitOfWorkRepository 5 { 6 /// <summary> 7 /// 持久化新增实体 8 /// </summary> 9 /// <param name="item">待新增实体接口</param> 10 void PersistNewItem(IEntity item); 11 12 /// <summary> 13 /// 持久化更新实体 14 /// </summary> 15 /// <param name="item">待更新实体接口</param> 16 void PersistUpdatedItem(IEntity item); 17 18 /// <summary> 19 /// 持久化删除实体 20 /// </summary> 21 /// <param name="item">待删除实体接口</param> 22 void PersistDeletedItem(IEntity item); 23 }
工作单元接口
1 /// <summary> 2 /// InvokeMethod 3 /// </summary> 4 /// <param name="entity"> 5 /// The entity. 6 /// </param> 7 public delegate void InvokeMethod(IEntity entity); 8 9 /// <summary> 10 /// 工作单元接口 11 /// </summary> 12 public interface IUnitOfWork : IDisposable 13 { 14 /// <summary> 15 /// .NET Framework 数据提供程序 16 /// </summary> 17 IDbCommand Command { get; } 18 19 /// <summary> 20 /// 提交工作单元 21 /// </summary> 22 void Complete(); 23 24 /// <summary> 25 /// 回滚工作单元 26 /// </summary> 27 void Rollback(); 28 29 /// <summary> 30 /// 注册新增实体工作单元仓储接口 31 /// </summary> 32 /// <param name="entity">待新增实体接口</param> 33 /// <param name="repository">工作单元仓储接口</param> 34 void RegisterAdded(IEntity entity, IUnitOfWorkRepository repository); 35 36 /// <summary> 37 /// 注册修改实体工作单元仓储接口 38 /// </summary> 39 /// <param name="entity">待修改实体接口</param> 40 /// <param name="repository">工作单元仓储接口</param> 41 void RegisterChanged(IEntity entity, IUnitOfWorkRepository repository); 42 43 /// <summary> 44 /// 注册删除实体工作单元仓储接口 45 /// </summary> 46 /// <param name="entity">待删除实体接口</param> 47 /// <param name="repository">工作单元仓储接口</param> 48 void RegisterRemoved(IEntity entity, IUnitOfWorkRepository repository); 49 50 /// <summary> 51 /// 注册一个其他非基础的增删改工作单元仓储接口 52 /// </summary> 53 /// <param name="entity">待操作实体接口</param> 54 /// <param name="methodName">自定义委托</param> 55 void RegisterInvokeMethod(IEntity entity, InvokeMethod methodName); 56 57 /// <summary> 58 /// 注册一个非继承聚合根的其他非基础的增删改工作单元仓储接口 59 /// </summary> 60 /// <param name="entity">待操作实体接口</param> 61 /// <param name="methodName">Func委托</param> 62 void RegisterInvokeMethod(object entity, Func<object, object> methodName); 63 }
工作单元
1 /// <summary> 2 /// 工作单元 3 /// </summary> 4 public class UnitOfWork : IUnitOfWork 5 { 6 /// <summary> 7 /// 新增实体工作单元 8 /// </summary> 9 private readonly Dictionary<IEntity, IUnitOfWorkRepository> m_addedEntities; 10 11 /// <summary> 12 /// 修改实体工作单元 13 /// </summary> 14 private readonly Dictionary<IEntity, IUnitOfWorkRepository> m_changedEntities; 15 16 /// <summary> 17 /// 删除实体工作单元 18 /// </summary> 19 private readonly Dictionary<IEntity, IUnitOfWorkRepository> m_deletedEntities; 20 21 /// <summary> 22 /// 其他非基础的增删改 23 /// </summary> 24 private readonly Dictionary<IEntity, InvokeMethod> m_invokeEntities; 25 26 /// <summary> 27 /// 非继承聚合根的其他非基础的增删改工作单元 28 /// </summary> 29 private readonly Dictionary<object, Func<object, object>> m_func; 30 31 /// <summary> 32 /// IDbConnection 33 /// </summary> 34 private IDbConnection m_connection; 35 36 /// <summary> 37 /// IDbCommand 38 /// </summary> 39 private IDbCommand m_command; 40 41 /// <summary> 42 /// IDbTransaction 43 /// </summary> 44 private IDbTransaction m_trans; 45 46 /// <summary> 47 /// Initializes a new instance of the <see cref="UnitOfWork"/> class. 48 /// </summary> 49 /// <param name="connectionSetting"> 50 /// The connection setting. 51 /// </param> 52 public UnitOfWork(string connectionSetting) 53 { 54 this.m_connection = DbFactories.GetConnection(connectionSetting); 55 this.m_command = this.m_connection.CreateCommand(); 56 this.m_trans = this.m_connection.BeginTransaction(); 57 this.m_command.Transaction = this.m_trans; 58 this.m_addedEntities = new Dictionary<IEntity, IUnitOfWorkRepository>(); 59 this.m_changedEntities = new Dictionary<IEntity, IUnitOfWorkRepository>(); 60 this.m_deletedEntities = new Dictionary<IEntity, IUnitOfWorkRepository>(); 61 this.m_invokeEntities = new Dictionary<IEntity, InvokeMethod>(); 62 this.m_func = new Dictionary<object, Func<object, object>>(); 63 } 64 65 /// <summary> 66 /// .NET Framework 数据提供程序 67 /// </summary> 68 public IDbCommand Command 69 { 70 get 71 { 72 return this.m_command; 73 } 74 } 75 76 /// <summary> 77 /// 提交工作单元 78 /// </summary> 79 public void Complete() 80 { 81 try 82 { 83 foreach (IEntity entity in this.m_deletedEntities.Keys) 84 { 85 this.m_deletedEntities[entity].PersistDeletedItem(entity); 86 } 87 88 foreach (IEntity entity in this.m_addedEntities.Keys) 89 { 90 this.m_addedEntities[entity].PersistNewItem(entity); 91 } 92 93 foreach (IEntity entity in this.m_changedEntities.Keys) 94 { 95 this.m_changedEntities[entity].PersistUpdatedItem(entity); 96 } 97 98 foreach (IEntity entity in this.m_invokeEntities.Keys) 99 { 100 this.m_invokeEntities[entity](entity); 101 } 102 103 foreach (var entity in this.m_func) 104 { 105 entity.Value(entity.Key); 106 } 107 108 this.m_trans.Commit(); 109 } 110 catch (Exception) 111 { 112 this.Rollback(); 113 } 114 finally 115 { 116 this.Dispose(); 117 this.Clear(); 118 } 119 } 120 121 /// <summary> 122 /// 回滚工作单元 123 /// </summary> 124 public void Rollback() 125 { 126 this.m_trans.Rollback(); 127 } 128 129 /// <summary> 130 /// 注册新增实体工作单元仓储接口 131 /// </summary> 132 /// <param name="entity">待新增实体接口</param> 133 /// <param name="repository">工作单元仓储接口</param> 134 public void RegisterAdded(IEntity entity, IUnitOfWorkRepository repository) 135 { 136 this.m_addedEntities.Add(entity, repository); 137 } 138 139 /// <summary> 140 /// 注册修改实体工作单元仓储接口 141 /// </summary> 142 /// <param name="entity">待修改实体接口</param> 143 /// <param name="repository">工作单元仓储接口</param> 144 public void RegisterChanged(IEntity entity, IUnitOfWorkRepository repository) 145 { 146 this.m_changedEntities.Add(entity, repository); 147 } 148 149 /// <summary> 150 /// 注册删除实体工作单元仓储接口 151 /// </summary> 152 /// <param name="entity">待删除实体接口</param> 153 /// <param name="repository">工作单元仓储接口</param> 154 public void RegisterRemoved(IEntity entity, IUnitOfWorkRepository repository) 155 { 156 this.m_deletedEntities.Add(entity, repository); 157 } 158 159 /// <summary> 160 /// 注册一个其他非基础的增删改工作单元仓储接口 161 /// </summary> 162 /// <param name="entity">待操作实体接口</param> 163 /// <param name="methodName">自定义委托</param> 164 public void RegisterInvokeMethod(IEntity entity, InvokeMethod methodName) 165 { 166 this.m_invokeEntities.Add(entity, methodName); 167 } 168 169 /// <summary> 170 /// 注册一个非继承聚合根的其他非基础的增删改工作单元仓储接口 171 /// </summary> 172 /// <param name="entity">待操作实体接口</param> 173 /// <param name="methodName">Func委托</param> 174 public void RegisterInvokeMethod(object entity, Func<object, object> methodName) 175 { 176 this.m_func.Add(entity, methodName); 177 } 178 179 /// <summary> 180 /// 释放资源 181 /// </summary> 182 public void Dispose() 183 { 184 if (this.m_trans != null) 185 { 186 this.m_trans.Dispose(); 187 this.m_trans = null; 188 } 189 190 if (this.m_command != null) 191 { 192 this.m_command.Dispose(); 193 this.m_command = null; 194 } 195 196 if (this.m_connection != null) 197 { 198 this.m_connection.Dispose(); 199 this.m_connection.Close(); 200 this.m_connection = null; 201 } 202 } 203 204 /// <summary> 205 /// 清除 206 /// </summary> 207 private void Clear() 208 { 209 this.m_addedEntities.Clear(); 210 this.m_changedEntities.Clear(); 211 this.m_deletedEntities.Clear(); 212 this.m_invokeEntities.Clear(); 213 this.m_func.Clear(); 214 } 215 }
6.仓储基类
主要是为了消除大量重复代码,仓储将从基类继承共同的代码,仓储基类会实现仓储接口IRepository<in TKey, TValue> 并且实现IUnitOfWorkRepository工作单元仓储接口
1 /// <summary> 2 /// The repository base. 3 /// </summary> 4 /// <typeparam name="TKey"> 5 /// </typeparam> 6 /// <typeparam name="TValue"> 7 /// </typeparam> 8 public abstract class RepositoryBase<TKey, TValue> : IRepository<TKey, TValue>, IUnitOfWorkRepository 9 where TValue : EntityBase<TKey> 10 { 11 /// <summary> 12 /// IUnitOfWork 13 /// </summary> 14 public IUnitOfWork UnitOfWork { get; private set; } 15 16 /// <summary> 17 /// Initializes a new instance of the <see cref="RepositoryBase{TKey,TValue}"/> class. 18 /// </summary> 19 protected RepositoryBase() 20 : this(null) 21 { 22 } 23 24 /// <summary> 25 /// Initializes a new instance of the <see cref="RepositoryBase{TKey,TValue}"/> class. 26 /// </summary> 27 /// <param name="unitOfWork"> 28 /// The unit of work. 29 /// </param> 30 protected RepositoryBase(IUnitOfWork unitOfWork) 31 { 32 this.UnitOfWork = unitOfWork; 33 } 34 35 /// <summary> 36 /// The find by. 37 /// </summary> 38 /// <param name="key"> 39 /// The key. 40 /// </param> 41 /// <returns> 42 /// The <see cref="TValue"/>. 43 /// </returns> 44 public abstract TValue FindBy(TKey key); 45 46 /// <summary> 47 /// The add. 48 /// </summary> 49 /// <param name="item"> 50 /// The item. 51 /// </param> 52 public void Add(TValue item) 53 { 54 if (this.UnitOfWork != null) 55 { 56 this.UnitOfWork.RegisterAdded(item, this); 57 } 58 } 59 60 /// <summary> 61 /// The this. 62 /// </summary> 63 /// <param name="key"> 64 /// The key. 65 /// </param> 66 /// <returns> 67 /// The <see cref="TValue"/>. 68 /// </returns> 69 public TValue this[TKey key] 70 { 71 get 72 { 73 return this.FindBy(key); 74 } 75 76 set 77 { 78 if (this.FindBy(key) == null) 79 { 80 this.Add(value); 81 } 82 else 83 { 84 this.Update(value); 85 } 86 } 87 } 88 89 /// <summary> 90 /// The remove. 91 /// </summary> 92 /// <param name="item"> 93 /// The item. 94 /// </param> 95 public void Remove(TValue item) 96 { 97 if (this.UnitOfWork != null) 98 { 99 this.UnitOfWork.RegisterRemoved(item, this); 100 } 101 } 102 103 /// <summary> 104 /// The update. 105 /// </summary> 106 /// <param name="item"> 107 /// The item. 108 /// </param> 109 public void Update(TValue item) 110 { 111 if (this.UnitOfWork != null) 112 { 113 this.UnitOfWork.RegisterChanged(item, this); 114 } 115 } 116 117 /// <summary> 118 /// The persist new item. 119 /// </summary> 120 /// <param name="item"> 121 /// The item. 122 /// </param> 123 public abstract void PersistNewItem(IEntity item); 124 125 /// <summary> 126 /// The persist updated item. 127 /// </summary> 128 /// <param name="item"> 129 /// The item. 130 /// </param> 131 public abstract void PersistUpdatedItem(IEntity item); 132 133 /// <summary> 134 /// The persist deleted item. 135 /// </summary> 136 /// <param name="item"> 137 /// The item. 138 /// </param> 139 public abstract void PersistDeletedItem(IEntity item); 140 }
7.SqlCe仓储基类
主要是一些操作数据库的方法,这样避免了使用DBHelper类
1 /// <summary> 2 /// The sql ce repository base. 3 /// </summary> 4 /// <typeparam name="TKey"> 5 /// </typeparam> 6 /// <typeparam name="TValue"> 7 /// </typeparam> 8 public abstract class SqlCeRepositoryBase<TKey, TValue> : RepositoryBase<TKey, TValue>, IDisposable 9 where TValue : EntityBase<TKey> 10 { 11 /// <summary> 12 /// The connection. 13 /// </summary> 14 protected IDbConnection Connection { get; private set; } 15 16 /// <summary> 17 /// The cmd. 18 /// </summary> 19 protected IDbCommand Command { get; private set; } 20 21 /// <summary> 22 /// Initializes a new instance of the <see cref="SqlCeRepositoryBase{TKey,TValue}"/> class. 23 /// </summary> 24 /// <param name="connectionSetting"> 25 /// The connection setting. 26 /// </param> 27 protected SqlCeRepositoryBase(string connectionSetting) 28 : this(null, connectionSetting) 29 { 30 } 31 32 /// <summary> 33 /// Initializes a new instance of the <see cref="SqlCeRepositoryBase{TKey,TValue}"/> class. 34 /// </summary> 35 /// <param name="unitOfWork"> 36 /// The unit of work. 37 /// </param> 38 /// <param name="connectionSetting"> 39 /// The connection setting. 40 /// </param> 41 protected SqlCeRepositoryBase(IUnitOfWork unitOfWork, string connectionSetting) 42 : base(unitOfWork) 43 { 44 if (UnitOfWork != null) 45 { 46 this.Command = UnitOfWork.Command; 47 } 48 else 49 { 50 if (this.Connection == null) 51 { 52 this.Connection = DbFactories.GetConnection(connectionSetting); 53 } 54 if (this.Connection.State != ConnectionState.Open) 55 { 56 this.Connection.Open(); 57 } 58 this.Command = Connection.CreateCommand(); 59 } 60 } 61 62 #region Parameter 63 64 /// <summary> 65 /// The create parameter. 66 /// </summary> 67 /// <param name="name"> 68 /// The name. 69 /// </param> 70 /// <returns> 71 /// The <see cref="IDbDataParameter"/>. 72 /// </returns> 73 private IDbDataParameter CreateParameter(string name) 74 { 75 IDbDataParameter param = this.Command.CreateParameter(); 76 param.ParameterName = name; 77 return param; 78 } 79 80 /// <summary> 81 /// The create parameter. 82 /// </summary> 83 /// <param name="name"> 84 /// The name. 85 /// </param> 86 /// <param name="value"> 87 /// The value. 88 /// </param> 89 /// <returns> 90 /// The <see cref="IDbDataParameter"/>. 91 /// </returns> 92 private IDbDataParameter CreateParameter(string name, object value) 93 { 94 IDbDataParameter param = CreateParameter(name); 95 param.Value = value ?? DBNull.Value; 96 return param; 97 } 98 99 /// <summary> 100 /// The create parameter. 101 /// </summary> 102 /// <param name="name"> 103 /// The name. 104 /// </param> 105 /// <param name="value"> 106 /// The value. 107 /// </param> 108 /// <param name="type"> 109 /// The type. 110 /// </param> 111 /// <returns> 112 /// The <see cref="IDbDataParameter"/>. 113 /// </returns> 114 private IDbDataParameter CreateParameter(string name, object value, DbType type) 115 { 116 IDbDataParameter param = CreateParameter(name, value); 117 param.DbType = type; 118 return param; 119 } 120 121 /// <summary> 122 /// The create parameter. 123 /// </summary> 124 /// <param name="name"> 125 /// The name. 126 /// </param> 127 /// <param name="value"> 128 /// The value. 129 /// </param> 130 /// <param name="type"> 131 /// The type. 132 /// </param> 133 /// <param name="direction"> 134 /// The direction. 135 /// </param> 136 /// <returns> 137 /// The <see cref="IDbDataParameter"/>. 138 /// </returns> 139 private IDbDataParameter CreateParameter(string name, object value, DbType type, ParameterDirection direction) 140 { 141 IDbDataParameter param = CreateParameter(name, value, type); 142 param.Direction = direction; 143 return param; 144 } 145 146 /// <summary> 147 /// The create parameter. 148 /// </summary> 149 /// <param name="name"> 150 /// The name. 151 /// </param> 152 /// <param name="value"> 153 /// The value. 154 /// </param> 155 /// <param name="type"> 156 /// The type. 157 /// </param> 158 /// <param name="direction"> 159 /// The direction. 160 /// </param> 161 /// <param name="size"> 162 /// The size. 163 /// </param> 164 /// <returns> 165 /// The <see cref="IDbDataParameter"/>. 166 /// </returns> 167 private IDbDataParameter CreateParameter(string name, object value, DbType type, ParameterDirection direction, int size) 168 { 169 IDbDataParameter param = CreateParameter(name, value, type, direction); 170 param.Size = size; 171 return param; 172 } 173 174 /// <summary> 175 /// The create parameter. 176 /// </summary> 177 /// <param name="name"> 178 /// The name. 179 /// </param> 180 /// <param name="value"> 181 /// The value. 182 /// </param> 183 /// <param name="type"> 184 /// The type. 185 /// </param> 186 /// <param name="direction"> 187 /// The direction. 188 /// </param> 189 /// <param name="size"> 190 /// The size. 191 /// </param> 192 /// <param name="scale"> 193 /// The scale. 194 /// </param> 195 /// <returns> 196 /// The <see cref="IDbDataParameter"/>. 197 /// </returns> 198 private IDbDataParameter CreateParameter(string name, object value, DbType type, ParameterDirection direction, int size, byte scale) 199 { 200 IDbDataParameter param = CreateParameter(name, value, type, direction, size); 201 param.Scale = scale; 202 return param; 203 } 204 205 /// <summary> 206 /// The add parameter. 207 /// </summary> 208 /// <param name="name"> 209 /// The name. 210 /// </param> 211 /// <returns> 212 /// The <see cref="IDbDataParameter"/>. 213 /// </returns> 214 protected IDbDataParameter AddParameter(string name) 215 { 216 IDbDataParameter param = CreateParameter(name); 217 this.Command.Parameters.Add(param); 218 return param; 219 } 220 221 /// <summary> 222 /// The add parameter. 223 /// </summary> 224 /// <param name="name"> 225 /// The name. 226 /// </param> 227 /// <param name="value"> 228 /// The value. 229 /// </param> 230 /// <returns> 231 /// The <see cref="IDbDataParameter"/>. 232 /// </returns> 233 protected IDbDataParameter AddParameter(string name, object value) 234 { 235 IDbDataParameter param = CreateParameter(name, value); 236 this.Command.Parameters.Add(param); 237 return param; 238 } 239 240 /// <summary> 241 /// The add parameter. 242 /// </summary> 243 /// <param name="name"> 244 /// The name. 245 /// </param> 246 /// <param name="value"> 247 /// The value. 248 /// </param> 249 /// <param name="type"> 250 /// The type. 251 /// </param> 252 /// <returns> 253 /// The <see cref="IDbDataParameter"/>. 254 /// </returns> 255 protected IDbDataParameter AddParameter(string name, object value, DbType type) 256 { 257 IDbDataParameter param = CreateParameter(name, value, type); 258 this.Command.Parameters.Add(param); 259 return param; 260 } 261 262 /// <summary> 263 /// The add parameter. 264 /// </summary> 265 /// <param name="name"> 266 /// The name. 267 /// </param> 268 /// <param name="value"> 269 /// The value. 270 /// </param> 271 /// <param name="type"> 272 /// The type. 273 /// </param> 274 /// <param name="direction"> 275 /// The direction. 276 /// </param> 277 /// <returns> 278 /// The <see cref="IDbDataParameter"/>. 279 /// </returns> 280 protected IDbDataParameter AddParameter(string name, object value, DbType type, ParameterDirection direction) 281 { 282 IDbDataParameter param = CreateParameter(name, value, type, direction); 283 this.Command.Parameters.Add(param); 284 return param; 285 } 286 287 /// <summary> 288 /// The add parameter. 289 /// </summary> 290 /// <param name="name"> 291 /// The name. 292 /// </param> 293 /// <param name="value"> 294 /// The value. 295 /// </param> 296 /// <param name="type"> 297 /// The type. 298 /// </param> 299 /// <param name="direction"> 300 /// The direction. 301 /// </param> 302 /// <param name="size"> 303 /// The size. 304 /// </param> 305 /// <returns> 306 /// The <see cref="IDbDataParameter"/>. 307 /// </returns> 308 protected IDbDataParameter AddParameter(string name, object value, DbType type, ParameterDirection direction, int size) 309 { 310 IDbDataParameter param = CreateParameter(name, value, type, direction, size); 311 this.Command.Parameters.Add(param); 312 return param; 313 } 314 315 /// <summary> 316 /// The add parameter. 317 /// </summary> 318 /// <param name="name"> 319 /// The name. 320 /// </param> 321 /// <param name="value"> 322 /// The value. 323 /// </param> 324 /// <param name="type"> 325 /// The type. 326 /// </param> 327 /// <param name="direction"> 328 /// The direction. 329 /// </param> 330 /// <param name="size"> 331 /// The size. 332 /// </param> 333 /// <param name="scale"> 334 /// The scale. 335 /// </param> 336 /// <returns> 337 /// The <see cref="IDbDataParameter"/>. 338 /// </returns> 339 protected IDbDataParameter AddParameter(string name, object value, DbType type, ParameterDirection direction, int size, byte scale) 340 { 341 IDbDataParameter param = CreateParameter(name, value, type, direction, size, scale); 342 this.Command.Parameters.Add(param); 343 return param; 344 } 345 346 /// <summary> 347 /// The clear parameters. 348 /// </summary> 349 protected void ClearParameters() 350 { 351 this.Command.Parameters.Clear(); 352 } 353 354 #endregion 355 356 #region ExecuteReader 357 358 /// <summary> 359 /// The execute reader. 360 /// </summary> 361 /// <param name="sql"> 362 /// The sql. 363 /// </param> 364 /// <param name="type"> 365 /// The type. 366 /// </param> 367 /// <param name="behavior"> 368 /// The behavior. 369 /// </param> 370 /// <param name="timeout"> 371 /// The timeout. 372 /// </param> 373 /// <returns> 374 /// The <see cref="IDataReader"/>. 375 /// </returns> 376 protected virtual IDataReader ExecuteReader(string sql, CommandType type, CommandBehavior behavior, int timeout) 377 { 378 if (string.IsNullOrWhiteSpace(sql)) 379 { 380 throw new ArgumentNullException("sql"); 381 } 382 this.Command.CommandText = sql; 383 this.Command.CommandType = type; 384 this.Command.CommandTimeout = timeout; 385 return this.Command.ExecuteReader(behavior); 386 } 387 388 /// <summary> 389 /// The execute reader. 390 /// </summary> 391 /// <param name="sql"> 392 /// The sql. 393 /// </param> 394 /// <param name="type"> 395 /// The type. 396 /// </param> 397 /// <param name="behavior"> 398 /// The behavior. 399 /// </param> 400 /// <returns> 401 /// The <see cref="IDataReader"/>. 402 /// </returns> 403 protected IDataReader ExecuteReader(string sql, CommandType type, CommandBehavior behavior) 404 { 405 return this.ExecuteReader(sql, type, behavior, 0); 406 } 407 408 /// <summary> 409 /// The execute reader. 410 /// </summary> 411 /// <param name="sql"> 412 /// The sql. 413 /// </param> 414 /// <param name="type"> 415 /// The type. 416 /// </param> 417 /// <param name="timeout"> 418 /// The timeout. 419 /// </param> 420 /// <returns> 421 /// The <see cref="IDataReader"/>. 422 /// </returns> 423 protected IDataReader ExecuteReader(string sql, CommandType type, int timeout) 424 { 425 return this.ExecuteReader(sql, type, CommandBehavior.Default, timeout); 426 } 427 428 /// <summary> 429 /// The execute reader. 430 /// </summary> 431 /// <param name="sql"> 432 /// The sql. 433 /// </param> 434 /// <param name="type"> 435 /// The type. 436 /// </param> 437 /// <returns> 438 /// The <see cref="IDataReader"/>. 439 /// </returns> 440 protected IDataReader ExecuteReader(string sql, CommandType type) 441 { 442 return this.ExecuteReader(sql, type, CommandBehavior.Default, 0); 443 } 444 445 /// <summary> 446 /// The execute reader. 447 /// </summary> 448 /// <param name="sql"> 449 /// The sql. 450 /// </param> 451 /// <param name="behavior"> 452 /// The behavior. 453 /// </param> 454 /// <param name="timeout"> 455 /// The timeout. 456 /// </param> 457 /// <returns> 458 /// The <see cref="IDataReader"/>. 459 /// </returns> 460 protected IDataReader ExecuteReader(string sql, CommandBehavior behavior, int timeout) 461 { 462 return this.ExecuteReader(sql, CommandType.Text, behavior, timeout); 463 } 464 465 /// <summary> 466 /// The execute reader. 467 /// </summary> 468 /// <param name="sql"> 469 /// The sql. 470 /// </param> 471 /// <param name="behavior"> 472 /// The behavior. 473 /// </param> 474 /// <returns> 475 /// The <see cref="IDataReader"/>. 476 /// </returns> 477 protected IDataReader ExecuteReader(string sql, CommandBehavior behavior) 478 { 479 return this.ExecuteReader(sql, CommandType.Text, behavior, 0); 480 } 481 482 /// <summary> 483 /// The execute reader. 484 /// </summary> 485 /// <param name="sql"> 486 /// The sql. 487 /// </param> 488 /// <param name="timeout"> 489 /// The timeout. 490 /// </param> 491 /// <returns> 492 /// The <see cref="IDataReader"/>. 493 /// </returns> 494 protected IDataReader ExecuteReader(string sql, int timeout) 495 { 496 return this.ExecuteReader(sql, CommandType.Text, CommandBehavior.Default, timeout); 497 } 498 499 /// <summary> 500 /// The execute reader. 501 /// </summary> 502 /// <param name="sql"> 503 /// The sql. 504 /// </param> 505 /// <returns> 506 /// The <see cref="IDataReader"/>. 507 /// </returns> 508 protected IDataReader ExecuteReader(string sql) 509 { 510 return this.ExecuteReader(sql, CommandType.Text, CommandBehavior.Default, 0); 511 } 512 513 #endregion 514 515 #region ExecuteTable 516 517 /// <summary> 518 /// The execute table. 519 /// </summary> 520 /// <param name="sql"> 521 /// The sql. 522 /// </param> 523 /// <param name="type"> 524 /// The type. 525 /// </param> 526 /// <param name="behavior"> 527 /// The behavior. 528 /// </param> 529 /// <param name="timeout"> 530 /// The timeout. 531 /// </param> 532 /// <returns> 533 /// The <see cref="DataTable"/>. 534 /// </returns> 535 protected virtual DataTable ExecuteTable(string sql, CommandType type, CommandBehavior behavior, int timeout) 536 { 537 using (IDataReader dr = ExecuteReader(sql, type, behavior, timeout)) 538 { 539 DataTable dt = new DataTable(); 540 dt.Load(dr); 541 return dt; 542 } 543 } 544 545 /// <summary> 546 /// The execute table. 547 /// </summary> 548 /// <param name="sql"> 549 /// The sql. 550 /// </param> 551 /// <param name="type"> 552 /// The type. 553 /// </param> 554 /// <param name="behavior"> 555 /// The behavior. 556 /// </param> 557 /// <returns> 558 /// The <see cref="DataTable"/>. 559 /// </returns> 560 protected DataTable ExecuteTable(string sql, CommandType type, CommandBehavior behavior) 561 { 562 return this.ExecuteTable(sql, type, behavior, 0); 563 } 564 565 /// <summary> 566 /// The execute table. 567 /// </summary> 568 /// <param name="sql"> 569 /// The sql. 570 /// </param> 571 /// <param name="type"> 572 /// The type. 573 /// </param> 574 /// <param name="timeout"> 575 /// The timeout. 576 /// </param> 577 /// <returns> 578 /// The <see cref="DataTable"/>. 579 /// </returns> 580 protected DataTable ExecuteTable(string sql, CommandType type, int timeout) 581 { 582 return this.ExecuteTable(sql, type, CommandBehavior.Default, timeout); 583 } 584 585 /// <summary> 586 /// The execute table. 587 /// </summary> 588 /// <param name="sql"> 589 /// The sql. 590 /// </param> 591 /// <param name="type"> 592 /// The type. 593 /// </param> 594 /// <returns> 595 /// The <see cref="DataTable"/>. 596 /// </returns> 597 protected DataTable ExecuteTable(string sql, CommandType type) 598 { 599 return this.ExecuteTable(sql, type, CommandBehavior.Default, 0); 600 } 601 602 /// <summary> 603 /// The execute table. 604 /// </summary> 605 /// <param name="sql"> 606 /// The sql. 607 /// </param> 608 /// <param name="behavior"> 609 /// The behavior. 610 /// </param> 611 /// <param name="timeout"> 612 /// The timeout. 613 /// </param> 614 /// <returns> 615 /// The <see cref="DataTable"/>. 616 /// </returns> 617 protected DataTable ExecuteTable(string sql, CommandBehavior behavior, int timeout) 618 { 619 return this.ExecuteTable(sql, CommandType.Text, behavior, timeout); 620 } 621 622 /// <summary> 623 /// The execute table. 624 /// </summary> 625 /// <param name="sql"> 626 /// The sql. 627 /// </param> 628 /// <param name="behavior"> 629 /// The behavior. 630 /// </param> 631 /// <returns> 632 /// The <see cref="DataTable"/>. 633 /// </returns> 634 protected DataTable ExecuteTable(string sql, CommandBehavior behavior) 635 { 636 return this.ExecuteTable(sql, CommandType.Text, behavior, 0); 637 } 638 639 /// <summary> 640 /// The execute table. 641 /// </summary> 642 /// <param name="sql"> 643 /// The sql. 644 /// </param> 645 /// <param name="timeout"> 646 /// The timeout. 647 /// </param> 648 /// <returns> 649 /// The <see cref="DataTable"/>. 650 /// </returns> 651 protected DataTable ExecuteTable(string sql, int timeout) 652 { 653 return this.ExecuteTable(sql, CommandType.Text, CommandBehavior.Default, timeout); 654 } 655 656 /// <summary> 657 /// The execute table. 658 /// </summary> 659 /// <param name="sql"> 660 /// The sql. 661 /// </param> 662 /// <returns> 663 /// The <see cref="DataTable"/>. 664 /// </returns> 665 protected DataTable ExecuteTable(string sql) 666 { 667 return this.ExecuteTable(sql, CommandType.Text, CommandBehavior.Default, 0); 668 } 669 670 #endregion 671 672 #region ExecuteDataSet 673 674 /// <summary> 675 /// The execute data set. 676 /// </summary> 677 /// <param name="sql"> 678 /// The sql. 679 /// </param> 680 /// <param name="tableName"> 681 /// The table name. 682 /// </param> 683 /// <returns> 684 /// The <see cref="DataSet"/>. 685 /// </returns> 686 public DataSet ExecuteDataSet(string sql, params string[] tableName) 687 { 688 return this.ExecuteDataSet(sql, CommandType.Text, tableName); 689 } 690 691 /// <summary> 692 /// The execute data set. 693 /// </summary> 694 /// <param name="sql"> 695 /// The sql. 696 /// </param> 697 /// <param name="type"> 698 /// The type. 699 /// </param> 700 /// <param name="tableName"> 701 /// The table name. 702 /// </param> 703 /// <returns> 704 /// The <see cref="DataSet"/>. 705 /// </returns> 706 public virtual DataSet ExecuteDataSet(string sql, CommandType type, params string[] tableName) 707 { 708 using (IDataReader dr = this.ExecuteReader(sql, type, CommandBehavior.Default, 0)) 709 { 710 DataSet ds = new DataSet(); 711 ds.Load(dr, LoadOption.Upsert, tableName); 712 return ds; 713 } 714 } 715 716 #endregion 717 718 #region ExecuteScalar 719 720 /// <summary> 721 /// The execute scalar. 722 /// </summary> 723 /// <param name="sql"> 724 /// The sql. 725 /// </param> 726 /// <param name="type"> 727 /// The type. 728 /// </param> 729 /// <param name="timeout"> 730 /// The timeout. 731 /// </param> 732 /// <returns> 733 /// The <see cref="object"/>. 734 /// </returns> 735 public virtual object ExecuteScalar(string sql, CommandType type, int timeout) 736 { 737 if (string.IsNullOrWhiteSpace(sql)) 738 { 739 throw new ArgumentNullException("sql"); 740 } 741 this.Command.CommandText = sql; 742 this.Command.CommandType = type; 743 this.Command.CommandTimeout = timeout; 744 return this.Command.ExecuteScalar(); 745 } 746 747 /// <summary> 748 /// The execute scalar. 749 /// </summary> 750 /// <param name="sql"> 751 /// The sql. 752 /// </param> 753 /// <param name="type"> 754 /// The type. 755 /// </param> 756 /// <returns> 757 /// The <see cref="object"/>. 758 /// </returns> 759 public object ExecuteScalar(string sql, CommandType type) 760 { 761 return this.ExecuteScalar(sql, type, 0); 762 } 763 764 /// <summary> 765 /// The execute scalar. 766 /// </summary> 767 /// <param name="sql"> 768 /// The sql. 769 /// </param> 770 /// <param name="timeout"> 771 /// The timeout. 772 /// </param> 773 /// <returns> 774 /// The <see cref="object"/>. 775 /// </returns> 776 public object ExecuteScalar(string sql, int timeout) 777 { 778 return this.ExecuteScalar(sql, CommandType.Text, timeout); 779 } 780 781 /// <summary> 782 /// The execute scalar. 783 /// </summary> 784 /// <param name="sql"> 785 /// The sql. 786 /// </param> 787 /// <returns> 788 /// The <see cref="object"/>. 789 /// </returns> 790 public object ExecuteScalar(string sql) 791 { 792 return this.ExecuteScalar(sql, CommandType.Text, 0); 793 } 794 795 #endregion 796 797 #region ExecuteNonQuery 798 799 /// <summary> 800 /// The execute non query. 801 /// </summary> 802 /// <param name="sql"> 803 /// The sql. 804 /// </param> 805 /// <param name="type"> 806 /// The type. 807 /// </param> 808 /// <param name="timeout"> 809 /// The timeout. 810 /// </param> 811 /// <returns> 812 /// The <see cref="int"/>. 813 /// </returns> 814 public virtual int ExecuteNonQuery(string sql, CommandType type, int timeout) 815 { 816 if (string.IsNullOrWhiteSpace(sql)) 817 { 818 throw new ArgumentNullException("sql"); 819 } 820 this.Command.CommandText = sql; 821 this.Command.CommandType = type; 822 this.Command.CommandTimeout = timeout; 823 return this.Command.ExecuteNonQuery(); 824 } 825 826 /// <summary> 827 /// The execute non query. 828 /// </summary> 829 /// <param name="sql"> 830 /// The sql. 831 /// </param> 832 /// <param name="type"> 833 /// The type. 834 /// </param> 835 /// <returns> 836 /// The <see cref="int"/>. 837 /// </returns> 838 public int ExecuteNonQuery(string sql, CommandType type) 839 { 840 return this.ExecuteNonQuery(sql, type, 0); 841 } 842 843 /// <summary> 844 /// The execute non query. 845 /// </summary> 846 /// <param name="sql"> 847 /// The sql. 848 /// </param> 849 /// <param name="timeout"> 850 /// The timeout. 851 /// </param> 852 /// <returns> 853 /// The <see cref="int"/>. 854 /// </returns> 855 public int ExecuteNonQuery(string sql, int timeout) 856 { 857 return this.ExecuteNonQuery(sql, CommandType.Text, timeout); 858 } 859 860 /// <summary> 861 /// The execute non query. 862 /// </summary> 863 /// <param name="sql"> 864 /// The sql. 865 /// </param> 866 /// <returns> 867 /// The <see cref="int"/>. 868 /// </returns> 869 public int ExecuteNonQuery(string sql) 870 { 871 return this.ExecuteNonQuery(sql, CommandType.Text, 0); 872 } 873 874 #endregion 875 876 /// <summary> 877 /// The dispose. 878 /// </summary> 879 public void Dispose() 880 { 881 if (this.Command != null) 882 { 883 this.Command.Dispose(); 884 this.Command = null; 885 } 886 887 if (this.Connection == null) 888 { 889 return; 890 } 891 892 if (this.Connection.State == ConnectionState.Open) 893 { 894 this.Connection.Close(); 895 } 896 897 this.Connection.Dispose(); 898 this.Connection = null; 899 } 900 }
8.Sql仓储基类
主要是加载有子对象的跟定义实体对象接口
1 /// <summary> 2 /// The sql repository base. 3 /// </summary> 4 /// <typeparam name="TKey"> 5 /// </typeparam> 6 /// <typeparam name="TValue"> 7 /// </typeparam> 8 public abstract class SqlRepositoryBase<TKey, TValue> : SqlCeRepositoryBase<TKey, TValue> 9 where TValue : EntityBase<TKey> 10 { 11 /// <summary> 12 /// 有子对象的回调委托 13 /// </summary> 14 /// <param name="entityAggregate">实体聚合根</param> 15 /// <param name="childEntityKeyValue">子实体键</param> 16 public delegate void AppendChildData(TValue entityAggregate, object childEntityKeyValue); 17 18 /// <summary> 19 /// 实体工厂 20 /// </summary> 21 private readonly IEntityFactory<TValue> m_entityFactory; 22 23 /// <summary> 24 /// 子对象集 25 /// </summary> 26 private readonly Dictionary<string, AppendChildData> m_childCallbacks; 27 28 /// <summary> 29 /// The m_child key datas. 30 /// </summary> 31 private readonly Dictionary<string, object> m_childKeyDatas; 32 33 /// <summary> 34 /// Initializes a new instance of the <see cref="SqlRepositoryBase{TKey,TValue}"/> class. 35 /// </summary> 36 /// <param name="connectionSetting"> 37 /// The connection setting. 38 /// </param> 39 protected SqlRepositoryBase(string connectionSetting) 40 : base(connectionSetting) 41 { 42 } 43 44 /// <summary> 45 /// Initializes a new instance of the <see cref="SqlRepositoryBase{TKey,TValue}"/> class. 46 /// </summary> 47 /// <param name="unitOfWork"> 48 /// The unit of work. 49 /// </param> 50 /// <param name="connectionSetting"> 51 /// The connection setting. 52 /// </param> 53 protected SqlRepositoryBase(IUnitOfWork unitOfWork, string connectionSetting) 54 : base(unitOfWork, connectionSetting) 55 { 56 this.m_entityFactory = this.BuildEntityFactory(); 57 this.m_childCallbacks = new Dictionary<string, AppendChildData>(); 58 this.m_childKeyDatas = new Dictionary<string, object>(); 59 this.BuildChildCallbacks(this.m_childCallbacks); 60 } 61 62 /// <summary> 63 /// 改为由子类创建实体,不使用工厂 64 /// </summary> 65 /// <returns>TValue</returns> 66 protected abstract IEntityFactory<TValue> BuildEntityFactory(); 67 68 /// <summary> 69 /// 创建子对象回调 70 /// </summary> 71 /// <param name="childCallbacks">子对象集</param> 72 protected abstract void BuildChildCallbacks(Dictionary<string, AppendChildData> childCallbacks); 73 74 /// <summary> 75 /// 子对象回调集 76 /// </summary> 77 protected Dictionary<string, AppendChildData> ChildCallbacks 78 { 79 get 80 { 81 return this.m_childCallbacks; 82 } 83 } 84 85 /// <summary> 86 /// The build entity from reader. 87 /// </summary> 88 /// <param name="reader"> 89 /// The reader. 90 /// </param> 91 /// <returns> 92 /// The <see cref="TValue"/>. 93 /// </returns> 94 protected virtual TValue BuildEntityFromReader(IDataReader reader) 95 { 96 TValue entity = this.m_entityFactory.BuildEntity(reader); 97 if (this.m_childCallbacks != null && this.m_childCallbacks.Count > 0) 98 { 99 DataTable columnData = reader.GetSchemaTable(); 100 foreach (string childKeyName in this.m_childCallbacks.Keys) 101 { 102 object childKeyValue; 103 ////判断 DataReader 的数据集合中是否存在一个特定的列名(或字段名) 104 if (columnData != null && columnData.Rows.Cast<DataRow>().Any(row => row["ColumnName"].ToString() == childKeyName)) 105 { 106 childKeyValue = reader[childKeyName]; 107 } 108 else 109 { 110 childKeyValue = null; 111 } 112 if (m_childKeyDatas.ContainsKey(childKeyName)) 113 { 114 m_childKeyDatas[childKeyName] = childKeyValue; 115 } 116 else 117 { 118 m_childKeyDatas.Add(childKeyName, childKeyValue); 119 } 120 } 121 } 122 return entity; 123 } 124 125 /// <summary> 126 /// The build entity from sql. 127 /// </summary> 128 /// <param name="sql"> 129 /// The sql. 130 /// </param> 131 /// <returns> 132 /// The <see cref="TValue"/>. 133 /// </returns> 134 protected virtual TValue BuildEntityFromSql(string sql) 135 { 136 TValue entity = default(TValue); 137 using (IDataReader reader = this.ExecuteReader(sql)) 138 { 139 if (reader.Read()) 140 { 141 entity = this.BuildEntityFromReader(reader); 142 } 143 } 144 if (entity != null) 145 { 146 this.InvokeChildCallbacks(entity); 147 } 148 return entity; 149 } 150 151 /// <summary> 152 /// The build entities from sql. 153 /// </summary> 154 /// <param name="sql"> 155 /// The sql. 156 /// </param> 157 /// <returns> 158 /// The 159 /// </returns> 160 protected virtual List<TValue> BuildEntitiesFromSql(string sql) 161 { 162 List<TValue> entities = new List<TValue>(); 163 using (IDataReader reader = this.ExecuteReader(sql)) 164 { 165 while (reader.Read()) 166 { 167 entities.Add(this.BuildEntityFromReader(reader)); 168 } 169 } 170 return entities; 171 } 172 173 /// <summary> 174 /// The invoke child callbacks. 175 /// </summary> 176 /// <param name="entity"> 177 /// The entity. 178 /// </param> 179 private void InvokeChildCallbacks(TValue entity) 180 { 181 if (this.m_childCallbacks != null && this.m_childCallbacks.Any()) 182 { 183 foreach (string childKeyName in this.m_childKeyDatas.Keys) 184 { 185 object childKeyValue; 186 this.m_childKeyDatas.TryGetValue(childKeyName, out childKeyValue); 187 this.m_childCallbacks[childKeyName](entity, childKeyValue); 188 } 189 } 190 } 191 }
领域层
1.分析业务需求,
假如我现在需要做一个平台的虚拟支付的功能(类似支付宝支付)
业务功能分析
1.开户功能
2.支付功能
3.转账功能
4.冻结解冻功能
2.结构设计
账户类图 Account账户类 Encrypted密保类 密保类又分手机邮箱。 账户类是继承EntityBase类的这样就抽象出他是一个聚合边界,从而对他抽象出仓储(仓储说白了就是保存到数据库的行为)
下面贴出仓储实现类的类图 ,AccountRepository 仓储类继承SqlRepositoryBase 并且继承仓储接口IAccountRepository 看他的方法主要实现了SqlRepositoryBase 的一些抽象方法而
仓储接口则是为空接口,这样做是为了方便后面扩展。
3.分析Account的职责
账户类型的一些基本职责跟行为
账户的职责就是拥有用户的基本新跟账户金额等等一些属性。
账户的基本行为:
1.登录
登录的时候需要验证账户状态是否可登录,等等一些信息
1 public void Login(string accountName, string loginPassWord) 2 { 3 this.ValidateEmpty(); 4 this.ValidateLoginStatus(); 5 if (this.AccountName != accountName) 6 { 7 throw new ArgumentException("抱歉!账户名错误"); 8 } 9 10 if (this.LoginPassWord != loginPassWord) 11 { 12 throw new ArgumentException("抱歉!账户登录密码错误"); 13 } 14 }
2.存款
存款其实也很简单只需要往账户余额上加钱就完事了
1 public void Deposit(decimal depositAmount) 2 { 3 this.Balance += depositAmount; 4 this.AvailableBalance += depositAmount; 5 }
3.取款
取款跟存款就相反了但是要注意一点就是需要验证余额是否充足
1 public void Withdraw(decimal withdrawAmout) 2 { 3 this.ValudateAvailableBalance(withdrawAmout); 4 this.Balance -= withdrawAmout; 5 this.AvailableBalance -= withdrawAmout; 6 }
5.冻结
冻结也跟取款类似
1 public void Freeze(decimal freezeAmount) 2 { 3 this.ValudateAvailableBalance(freezeAmount); 4 this.FreezeAmount += freezeAmount; 5 this.AvailableBalance -= freezeAmount; 6 }
6.解冻
解冻就跟冻结相反需要注意的就是验证可解冻金额范围
1 public void UnFreeze(decimal unFreezeAmount) 2 { 3 this.ValudateFreezeAmount(unFreezeAmount); 4 this.FreezeAmount -= unFreezeAmount; 5 this.AvailableBalance += unFreezeAmount; 6 }
7.修改交易密码
1 public void UpdatePayPassWord(string payPassWord) 2 { 3 this.PayPassWord = payPassWord; 4 }
8.修改登录密码
1 public void UpdateLoginPassWord(string loginPassWord) 2 { 3 this.LoginPassWord = loginPassWord; 4 }
4.AccountRepository实现的基本方法
主要是实现Account实体对象的 增删查改4个基本方法另外还有2个多的方法
BuildEntityFactory:用来创建读取IDataReader对象的接口
该方法返回一个IEntityFactory<Account>类型
这里只需要新建一个类AccountFactory实现IEntityFactory<out, T>接口即可
1 /// <summary> 2 /// The account factory. 3 /// </summary> 4 public class AccountFactory : IEntityFactory<Account> 5 { 6 /// <summary> 7 /// 把IDataReader对象解析成Account对象 8 /// </summary> 9 /// <param name="reader"> 10 /// The reader. 11 /// </param> 12 /// <returns> 13 /// The <see cref="Account"/>. 14 /// </returns> 15 public Account BuildEntity(IDataReader reader) 16 { 17 Account account = new Account(Guid.Parse(reader[FieldNames.AccountID].ToString())); 18 return account; 19 } 20 21 /// <summary> 22 /// 把DataSet对象解析成Account对象 23 /// </summary> 24 /// <param name="table"> 25 /// The table. 26 /// </param> 27 /// <returns> 28 /// The <see cref="Account"/>. 29 /// </returns> 30 public Account BuildEntity(DataSet table) 31 { 32 throw new NotImplementedException(); 33 } 34 35 /// <summary> 36 /// 映射数据库字段名称 37 /// </summary> 38 public static class FieldNames 39 { 40 /// <summary> 41 /// 表名 Account 42 /// </summary> 43 public const string Account = "Account"; 44 45 /// <summary> 46 /// 主键 AccountID 47 /// </summary> 48 public const string AccountID = "AccountID"; 49 } 50 }
1 protected override IEntityFactory<Account> BuildEntityFactory() 2 { 3 return new AccountFactory(); 4 }
BuildChildCallbacks:有来加载Acount的外键实体对象
因为Account对象的属性Encrypted密保对象数据保存在其他的表所以这里就把他当成子对象来加载
1 /// <summary> 2 /// The build child callbacks. 3 /// </summary> 4 /// <param name="childCallbacks"> 5 /// The child callbacks. 6 /// </param> 7 protected override void BuildChildCallbacks(Dictionary<string, AppendChildData> childCallbacks) 8 { 9 // 主要实现加载密保的方法 10 childCallbacks.Add( 11 AccountFactory.FieldNames.AccountID, 12 (a, b) => 13 { 14 // 此处调用加载密保的方法 15 a.Encrypted = null; 16 }); 17 }
下面贴出增删查改的方法 只实现了增加的方法做为实例
1 /// <summary> 2 /// 查询 3 /// </summary> 4 /// <param name="key"> 5 /// The key. 6 /// </param> 7 /// <returns> 8 /// The <see cref="Account"/>. 9 /// </returns> 10 public override Account FindBy(Guid key) 11 { 12 throw new NotImplementedException(); 13 } 14 15 /// <summary> 16 /// 增加 17 /// </summary> 18 /// <param name="item"> 19 /// The item. 20 /// </param> 21 public override void PersistNewItem(IEntity item) 22 { 23 // 因为Account是继承自IEntity接口这里直接把item转化成Account类型即可 24 Account account = (Account)item; 25 StringBuilder sql = new StringBuilder(); 26 sql.AppendFormat(" INSERT INTO {0}", AccountFactory.FieldNames.Account); 27 sql.Append(" ( "); 28 sql.AppendFormat("{0}", AccountFactory.FieldNames.AccountID); 29 sql.Append(" ) VALUES ( "); 30 sql.AppendFormat("@{0}", AccountFactory.FieldNames.AccountID); 31 sql.Append(");"); 32 33 // 调用父亲类方法实现参数化添加参数 34 // 调用支持先清除一下这是必须的 35 this.ClearParameters(); 36 this.AddParameter("@" + AccountFactory.FieldNames.AccountID, account.Key); 37 38 // 执行sql语句 39 this.ExecuteNonQuery(sql.ToString()); 40 } 41 42 /// <summary> 43 /// 修改 44 /// </summary> 45 /// <param name="item"> 46 /// The item. 47 /// </param> 48 public override void PersistUpdatedItem(IEntity item) 49 { 50 throw new NotImplementedException(); 51 } 52 53 /// <summary> 54 /// 删除 55 /// </summary> 56 /// <param name="item"> 57 /// The item. 58 /// </param> 59 public override void PersistDeletedItem(IEntity item) 60 { 61 throw new NotImplementedException(); 62 }
5.现在来实现开户功能
领域结构大致已经说完 现在来说最关心的业务了 第一个业务就是开户了
现在我们需要一个服务类AccountService(这个类的方法基本为静态方法 主要是把各个领域的领域逻辑组织起来现成连贯的业务逻辑)
现在先定义一个方法签名 public static void Register(AccountDTO accountDTO)开户的方法签名
AccountDTO 这个参数实际就是一个传输对象单独封装在一个程序集里面
他的属性主要就是开户的时候录入用户填写的一些信息
1 /// <summary> 2 /// 账户传输对象 3 /// </summary> 4 public class AccountDTO 5 { 6 /// <summary> 7 /// 账户名 8 /// </summary> 9 public string AccountName { get; set; } 10 11 /// <summary> 12 /// 昵称 13 /// </summary> 14 public string Nickname { get; set; } 15 16 /// <summary> 17 /// 登录密码 18 /// </summary> 19 public string LoginPassWord { get; set; } 20 21 /// <summary> 22 /// 交易密码 23 /// </summary> 24 public string PayPassWord { get; set; } 25 26 /// <summary> 27 /// 邮箱 28 /// </summary> 29 public string Emial { get; set; } 30 31 /// <summary> 32 /// 手机 33 /// </summary> 34 public string Phone { get; set; } 35 36 /// <summary> 37 /// 备注 38 /// </summary> 39 public string Remark { get; set; } 40 }
下一下步就是要把AccountDTO传输对象转化成Account领域对象
转化的时候我们就需要一个工厂类来创建
1 /// <summary> 2 /// Builder 3 /// </summary> 4 public class Builder 5 { 6 /// <summary> 7 /// 创建Account 8 /// </summary> 9 /// <param name="accountDTO">accountDTO</param> 10 /// <returns>Account</returns> 11 internal static Account BuilderAccount(AccountDTO accountDTO) 12 { 13 Account account = new Account 14 { 15 AccountStatus = AccountStatus.Normal, 16 Balance = 0M, 17 AvailableBalance = 0M, 18 FreezeAmount = 0M, 19 Encrypted = null, 20 AccountName = accountDTO.AccountName, 21 Nickname = accountDTO.Nickname, 22 LoginPassWord = accountDTO.LoginPassWord, 23 PayPassWord = accountDTO.PayPassWord, 24 Remark = accountDTO.Remark 25 }; 26 27 return account; 28 } 29 }
拿到Account对对象因为没有什么逻辑 就直接持久化到数据库了
这时候只需要通过IAccountRepository的Add方法把数据插入到数据库即可
IAccountRepository接口我们通过工厂方法创建
1 /// <summary> 2 /// The create i account repository. 3 /// </summary> 4 /// <returns> 5 /// The <see cref="IAccountRepository"/>. 6 /// </returns> 7 internal static IAccountRepository CreateIAccountRepository() 8 { 9 return new AccountRepository(ConnectionString.Account); 10 }
1 /// <summary> 2 /// The connection string. 3 /// </summary> 4 public static class ConnectionString 5 { 6 /// <summary> 7 /// The account. 8 /// </summary> 9 public const string Account = "Account"; 10 }
最后贴出开户的全部代码
1 public static void Register(AccountDTO accountDTO) 2 { 3 Account.Account account = Account.Builder.BuilderAccount(accountDTO); 4 using (IAccountRepository accountRepository = Account.Factory.AccountFactory.CreateIAccountRepository()) 5 { 6 accountRepository.Add(account); 7 } 8 }
6.既然用了账户当然我们就可以支付了
现在开始来实现支付,其实支付就是一种交易 既然交易肯定有买家,卖家这时候就抽象一个交易类来咯
Tread(交易类)
1 /// <summary> 2 /// 交易 3 /// </summary> 4 public class Trade : EntityBase<Guid> 5 { 6 /// <summary> 7 /// Initializes a new instance of the <see cref="Trade"/> class. 8 /// </summary> 9 public Trade() 10 : base(Guid.NewGuid()) 11 { 12 } 13 14 /// <summary> 15 /// Initializes a new instance of the <see cref="Trade"/> class. 16 /// </summary> 17 /// <param name="accountID"> 18 /// The account id. 19 /// </param> 20 public Trade(Guid accountID) 21 : base(accountID) 22 { 23 } 24 25 /// <summary> 26 /// 买家 27 /// </summary> 28 public Account Buyer { get; set; } 29 30 /// <summary> 31 /// 卖家 32 /// </summary> 33 public Account Seller { get; set; } 34 }
现在我们需要的是支付交易只需要再新建一个支付类就可以了
这个类主要包括支付的一些信息
1 /// <summary> 2 /// 支付 3 /// </summary> 4 public class PayOrder : Trade 5 { 6 /// <summary> 7 /// 支付状态 8 /// </summary> 9 public PayStatus PayStatus { get; set; } 10 11 /// <summary> 12 /// 支付金额 13 /// </summary> 14 public decimal PayAmount { get; set; } 15 16 /// <summary> 17 /// 支付订单号 18 /// </summary> 19 public string PayOrderNumber { get; set; } 20 21 /// <summary> 22 /// 创建时间 23 /// </summary> 24 public DateTime CreateDateTime { get; set; } 25 26 /// <summary> 27 /// 支付时间 28 /// </summary> 29 public DateTime? PayDateTime { get; set; } 30 31 /// <summary> 32 /// 备注 33 /// </summary> 34 public string Remark { get; set; } 35 36 /// <summary> 37 /// 支付 38 /// </summary> 39 /// <returns>生成账单</returns> 40 public List<Bill> Pay() 41 { 42 AccountService.AccountTransfer(this.Buyer, this.Seller, this.PayAmount); 43 return null; 44 } 45 }
需要注意的是这个类里面包括了一个支付的方法 这个方法返回支付的账单信息集合
1 /// <summary> 2 /// 账单 3 /// </summary> 4 public class Bill : EntityBase<Guid> 5 { 6 /// <summary> 7 /// 交易金额 8 /// </summary> 9 public decimal TradeAmount { get; set; } 10 11 /// <summary> 12 /// 账单流水号 13 /// </summary> 14 public string OrderNumber { get; set; } 15 16 /// <summary> 17 /// 交易类型 18 /// </summary> 19 public string TraderType { get; set; } 20 21 /// <summary> 22 /// 交易备注 23 /// </summary> 24 public string TradeRemark { get; set; } 25 26 /// <summary> 27 /// 交易时间 28 /// </summary> 29 public DateTime TradeDateTime { get; set; } 30 31 /// <summary> 32 /// 交易号 33 /// </summary> 34 public string TradeOrderNumber { get; set; } 35 36 /// <summary> 37 /// 交易账户 38 /// </summary> 39 public Account Account { get; set; } 40 41 /// <summary> 42 /// 交易对方账户 43 /// </summary> 44 public Account ToAccount { get; set; } 45 }
这样一来只需要把业务组织起来就可以完成支付了
还是跟开户一样先给支付服务的方法签名 public static void Pay(PayDTO payDTO)
PayDTO传输对象没有什么好说的
1 /// <summary> 2 /// 支付传送对象 3 /// </summary> 4 public class PayDTO 5 { 6 /// <summary> 7 /// 支付账号 8 /// </summary> 9 public string PayAccountNO { get; set; } 10 11 /// <summary> 12 /// 支付金额 13 /// </summary> 14 public decimal PayAmount { get; set; } 15 16 /// <summary> 17 /// 交易密码 18 /// </summary> 19 public string PayPassWord { get; set; } 20 21 /// <summary> 22 /// 交易备注 23 /// </summary> 24 public string Remark { get; set; } 25 }
1.验证支付信息就没有什么好说的了
2.根据支付账号加载支付账户
3.根据配置加载收款账户
4.创建支付订单
5.调用支付方法并且生成账单
1 /// <summary> 2 /// 支付 3 /// </summary> 4 /// <param name="payDTO">支付信息</param> 5 public static void Pay(PayDTO payDTO) 6 { 7 // 1 校验基本信息 8 payDTO.ValidatePayDTO(); 9 10 // 2 加载账户 11 // 支付账户 12 Account.Account payAccount = QueryByAccountName(payDTO.PayAccountNO); 13 14 // 收款账户 15 Account.Account sellerAccount = QueryBySeller(); 16 17 // 3 校验交易密码 18 payAccount.ValidatePayPassWord(payDTO.PayPassWord); 19 20 // 4 创建支付订单 21 PayOrder payOrder = Builder.BuilderPayOrder(payAccount, sellerAccount, payDTO); 22 23 // 同步处理为支付成功 24 payOrder.PaySucess(); 25 26 // 5 调用支付方法 27 List<Bill> bills = payOrder.Pay(); 28 29 // 6 持久化数据(开启工作单元;开启数据库事务) 30 using (IUnitOfWork unitOfWork = Account.Factory.AccountFactory.CreateIUnitOfWork()) 31 { 32 // 更新账户余额 33 IAccountRepository accountRepository = Account.Factory.AccountFactory.CreateIAccountRepository(unitOfWork); 34 accountRepository.Update(payAccount); 35 accountRepository.Update(sellerAccount); 36 37 // 生成订单 38 IPayOrderRepository payOrderRepository = Account.Factory.AccountFactory.CreateIPayOrderRepository(unitOfWork); 39 payOrderRepository.Add(payOrder); 40 41 // 生成账单 42 IBillRepository billRepository = Account.Factory.AccountFactory.CreateIBillRepository(unitOfWork); 43 billRepository.Add(bills); 44 45 // 提交工作单元(提交事务,失败自动回滚) 46 unitOfWork.Complete(); 47 } 48 }
7.转账
转账也是一种交易跟支付差不多 转账也需要继承至Trade交易类,因为转账属性正向业务,所以抽象一层ForwardTrade正向交易类
1 /// <summary> 2 /// 正向交易 3 /// </summary> 4 public class ForwardTrade : Trade 5 { 6 /// <summary> 7 /// Initializes a new instance of the <see cref="ForwardTrade"/> class. 8 /// </summary> 9 public ForwardTrade() 10 { 11 this.TradeOrderNumber = Builder.BuilderOrderNumber(); 12 } 13 14 /// <summary> 15 /// Initializes a new instance of the <see cref="ForwardTrade"/> class. 16 /// </summary> 17 /// <param name="tradeID"> 18 /// The pay order id. 19 /// </param> 20 public ForwardTrade(Guid tradeID) 21 : base(tradeID) 22 { 23 } 24 25 /// <summary> 26 /// 交易金额 27 /// </summary> 28 public decimal TradeAmount { get; set; } 29 30 /// <summary> 31 /// 交易订单号 32 /// </summary> 33 public string TradeOrderNumber { get; set; } 34 35 /// <summary> 36 /// 创建时间 37 /// </summary> 38 public DateTime CreateDateTime { get; set; } 39 40 /// <summary> 41 /// 支付时间 42 /// </summary> 43 public DateTime? TradeDateTime { get; set; } 44 45 /// <summary> 46 /// 备注 47 /// </summary> 48 public string Remark { get; set; } 49 50 /// <summary> 51 /// 更新交易时间 52 /// </summary> 53 /// <param name="tradeDateTime">交易时间</param> 54 public void UpdateTradeDateTime(DateTime tradeDateTime) 55 { 56 this.TradeDateTime = tradeDateTime; 57 } 58 59 /// <summary> 60 /// 交易 61 /// </summary> 62 /// <returns>生成账单</returns> 63 public List<TradeBill> Trade() 64 { 65 AccountService.AccountTransfer(this.Buyer, this.Seller, this.TradeAmount); 66 List<TradeBill> result = new List<TradeBill> 67 { 68 this.CreateBill(this.Buyer, this.Seller, TraderType.Out), 69 this.CreateBill(this.Seller, this.Buyer, TraderType.In) 70 }; 71 return result; 72 } 73 74 /// <summary> 75 /// 创建账单 76 /// </summary> 77 /// <param name="account">交易账户</param> 78 /// <param name="toAccount">交易对方账户</param> 79 /// <param name="traderType">交易类型</param> 80 /// <returns></returns> 81 private TradeBill CreateBill(Account account, Account toAccount, TraderType traderType) 82 { 83 return new TradeBill 84 { 85 Account = account, 86 ToAccount = toAccount, 87 TraderType = traderType, 88 TradeRemark = this.Remark, 89 TradeAmount = this.TradeAmount, 90 TradeDateTime = DateTime.Now, 91 TradeOrderNumber = this.TradeOrderNumber, 92 Balance = account.Balance, 93 AvailableBalance = account.AvailableBalance, 94 FreezeAmount = account.FreezeAmount, 95 BillType = BillType.Pay 96 }; 97 } 98 }
转账类只需要继承正向交易类就行了 转账只有一个转账的核心方法
1 /// <summary> 2 /// Transfer 3 /// </summary> 4 public class TransferOrder : ForwardTrade 5 { 6 /// <summary> 7 /// Initializes a new instance of the <see cref="TransferOrder"/> class. 8 /// </summary> 9 public TransferOrder() 10 { 11 } 12 13 /// <summary> 14 /// Initializes a new instance of the <see cref="TransferOrder"/> class. 15 /// </summary> 16 /// <param name="transferID"> 17 /// The pay order id. 18 /// </param> 19 public TransferOrder(Guid transferID) 20 : base(transferID) 21 { 22 } 23 24 /// <summary> 25 /// 状态 26 /// </summary> 27 public TransferStatus TransferStatus { get; set; } 28 29 /// <summary> 30 /// 支付成功处理 31 /// </summary> 32 public void TransferSucess() 33 { 34 if (this.TransferStatus == TransferStatus.Successful) 35 { 36 throw new ArgumentException("抱歉!订单已经交易成功"); 37 } 38 39 this.UpdateTradeDateTime(DateTime.Now); 40 this.UpdatePayStatus(TransferStatus.Successful); 41 } 42 43 /// <summary> 44 /// 转账 45 /// </summary> 46 /// <returns>账单</returns> 47 public List<TradeBill> Transfer() 48 { 49 return this.Trade(); 50 } 51 52 /// <summary> 53 /// 修改订单状态 54 /// </summary> 55 /// <param name="transferStatus">订单状态</param> 56 public void UpdatePayStatus(TransferStatus transferStatus) 57 { 58 this.TransferStatus = transferStatus; 59 } 60 }
最后在服务类组装业务
1 校验基本信息
2 加载 转账账户
3 加载收款账户
4 校验交易密码
5 创建订单
6 调用转账方法
7 持久化数据
1 /// <summary> 2 /// 转账 3 /// </summary> 4 /// <param name="transferDTO">转账信息</param> 5 public static void Transfer(TransferDTO transferDTO) 6 { 7 // 1 校验基本信息 8 transferDTO.ValidateTransferDTO(); 9 10 // 2 加载账户 11 // 转账账户 12 Account.Account payAccount = QueryByAccountName(transferDTO.TransferNO); 13 14 // 收款账户 15 Account.Account sellerAccount = QueryByAccountName(transferDTO.CollectionNO); 16 17 // 3 校验交易密码 18 payAccount.ValidatePayPassWord(transferDTO.PayPassWord); 19 20 // 4 创建订单 21 TransferOrder transferOrder = Builder.BuilderTransferOrder(payAccount, sellerAccount, transferDTO); 22 23 // 同步处理为成功 24 transferOrder.TransferSucess(); 25 26 // 5 调用转账方法 27 List<TradeBill> bills = transferOrder.Transfer(); 28 29 // 6 持久化数据(开启工作单元;开启数据库事务) 30 using (IUnitOfWork unitOfWork = Account.Factory.AccountFactory.CreateIUnitOfWork()) 31 { 32 // 更新账户余额 33 IAccountRepository accountRepository = Account.Factory.AccountFactory.CreateIAccountRepository(unitOfWork); 34 accountRepository.Update(payAccount); 35 accountRepository.Update(sellerAccount); 36 37 // 生成订单 38 ITransferOrderRepsoitory transferOrderRepsoitory = Account.Factory.AccountFactory.CreateITransferOrderRepsoitory(unitOfWork); 39 transferOrderRepsoitory.Add(transferOrder); 40 41 // 生成账单 42 IBillRepository billRepository = Account.Factory.AccountFactory.CreateIBillRepository(unitOfWork); 43 billRepository.Add(bills); 44 45 // 提交工作单元(提交事务,失败自动回滚) 46 unitOfWork.Complete(); 47 } 48 }
8.冻结
冻结主要是将账户的可用余额冻结起来 ,其实就实现一个内部转账就是账户自身AvailableBalance可用余额转到FreezeAmount冻结金额上去 最终生成冻结订单来控制金额变化起到资金控制的作用
这样就可以抽象出一个资金控制类出来
1 /// <summary> 2 /// 资金控制 3 /// </summary> 4 public class Control : EntityBase<Guid> 5 { 6 /// <summary> 7 /// Initializes a new instance of the <see cref="Control"/> class. 8 /// </summary> 9 public Control() 10 : base(Guid.NewGuid()) 11 { 12 } 13 14 /// <summary> 15 /// Initializes a new instance of the <see cref="Control"/> class. 16 /// </summary> 17 /// <param name="accountID"> 18 /// The account id. 19 /// </param> 20 public Control(Guid accountID) 21 : base(accountID) 22 { 23 } 24 25 /// <summary> 26 /// 控制账户 27 /// </summary> 28 public Account Account { get; set; } 29 }
这样再去设计冻结订单类
1 /// <summary> 2 /// 冻结订单 3 /// </summary> 4 public class FreezeOrder : Control 5 { 6 /// <summary> 7 /// Initializes a new instance of the <see cref="FreezeOrder"/> class. 8 /// </summary> 9 public FreezeOrder() 10 { 11 this.FrezeOrderNumber = Builder.BuilderOrderNumber(); 12 } 13 14 /// <summary> 15 /// 冻结订单号 16 /// </summary> 17 public string FrezeOrderNumber { get; set; } 18 19 /// <summary> 20 /// 冻结状态 21 /// </summary> 22 public FreezeStatus FreezeStatus { get; set; } 23 24 /// <summary> 25 /// 冻结金额 26 /// </summary> 27 public decimal FreezeAmount { get; set; } 28 29 /// <summary> 30 /// 已解冻金额 31 /// </summary> 32 public decimal ThawAmount { get; set; } 33 34 /// <summary> 35 /// 备注 36 /// </summary> 37 public string FreezeRemark { get; set; } 38 39 /// <summary> 40 /// 冻结 41 /// </summary> 42 /// <returns> 43 /// The 44 /// </returns> 45 public ControlBill Freeze() 46 { 47 this.Account.Freeze(this.FreezeAmount); 48 this.UpdateFreezeStatus(FreezeStatus.冻结成功); 49 return this.CreateControlBill(); 50 } 51 52 /// <summary> 53 /// 修改冻结订单状态 54 /// </summary> 55 /// <param name="freezeStatus">冻结订单状态</param> 56 public void UpdateFreezeStatus(FreezeStatus freezeStatus) 57 { 58 this.FreezeStatus = freezeStatus; 59 } 60 61 /// <summary> 62 /// 解冻 63 /// </summary> 64 /// <param name="thawAmount">解冻金额</param> 65 public void Thaw(decimal thawAmount) 66 { 67 if (thawAmount > this.FreezeAmount) 68 { 69 throw new AggregateException("抱歉!解冻金额大于冻结金额"); 70 } 71 72 if (thawAmount > this.FreezeAmount - this.ThawAmount) 73 { 74 throw new AggregateException("抱歉!解冻金额过大"); 75 } 76 77 this.ThawAmount += thawAmount; 78 } 79 80 /// <summary> 81 /// The create control bill. 82 /// </summary> 83 /// <returns> 84 /// The <see cref="ControlBill"/>. 85 /// </returns> 86 private ControlBill CreateControlBill() 87 { 88 var bill = new ControlBill 89 { 90 Account = this.Account, 91 Balance = this.Account.Balance, 92 AvailableBalance = this.Account.AvailableBalance, 93 FreezeAmount = this.Account.FreezeAmount, 94 ControlAmount = this.FreezeAmount, 95 ControlDateTime = DateTime.Now, 96 ControlOrderNumber = this.FrezeOrderNumber, 97 ControlRemark = this.FreezeRemark, 98 ControlType = ControlType.Freeze, 99 OrderNumber = Builder.BuilderOrderNumber() 100 }; 101 102 return bill; 103 } 104 }
冻结包括2个核心方法冻结跟解冻
服务类只需要组装这些业务冻结功能就完成了
1 /// <summary> 2 /// 冻结 3 /// </summary> 4 /// <param name="freezeDTO">冻结信息</param> 5 public static void Freeze(FreezeDTO freezeDTO) 6 { 7 freezeDTO.ValidateFreezeDTO(); 8 Account.Account account = QueryByAccountName(freezeDTO.FreezeNO); 9 FreezeOrder freezeOrder = Builder.BuilderFreezeOrder(account, freezeDTO); 10 ControlBill controlBill = freezeOrder.Freeze(); 11 using (IUnitOfWork unitOfWork = Account.Factory.AccountFactory.CreateIUnitOfWork()) 12 { 13 IAccountRepository accountRepository = Account.Factory.AccountFactory.CreateIAccountRepository(unitOfWork); 14 accountRepository.UpdateFreezeAmount(account); 15 16 // 生成冻结订单 17 IFreezeOrderRepository freezeOrderRepository = Account.Factory.AccountFactory.CreateIFreezeOrderRepository(unitOfWork); 18 freezeOrderRepository.Add(freezeOrder); 19 20 // 生成冻结账单 21 IControlBillRepository controlBillRepository = Account.Factory.AccountFactory.CreateIControlBillRepository(unitOfWork); 22 controlBillRepository.Add(controlBill); 23 24 unitOfWork.Complete(); 25 } 26 }
9.解冻
解冻与冻结就相反了
但是也是属于资金控制
只需要设计一个解冻订单类继承资金控制就可以,解冻订单必须包含一个属性是冻结订单
1 /// <summary> 2 /// 解冻订单 3 /// </summary> 4 public class ThawOrder : Control 5 { 6 /// <summary> 7 /// Initializes a new instance of the <see cref="ThawOrder"/> class. 8 /// </summary> 9 /// <param name="freezeOrder"> 10 /// The freeze order. 11 /// </param> 12 public ThawOrder(FreezeOrder freezeOrder) 13 { 14 this.Initialization(freezeOrder); 15 } 16 17 /// <summary> 18 /// Initializes a new instance of the <see cref="ThawOrder"/> class. 19 /// </summary> 20 /// <param name="thawId"> 21 /// The thaw id. 22 /// </param> 23 /// <param name="freezeOrder"> 24 /// The freeze order. 25 /// </param> 26 public ThawOrder(Guid thawId, FreezeOrder freezeOrder) 27 : base(thawId) 28 { 29 this.Initialization(freezeOrder); 30 } 31 32 /// <summary> 33 /// The initialization. 34 /// </summary> 35 /// <param name="freezeOrder"> 36 /// The freeze order. 37 /// </param> 38 private void Initialization(FreezeOrder freezeOrder) 39 { 40 this.FreezeOrder = freezeOrder; 41 this.Account = freezeOrder.Account; 42 } 43 44 /// <summary> 45 /// 冻结订单 46 /// </summary> 47 public FreezeOrder FreezeOrder { get; private set; } 48 49 /// <summary> 50 /// 冻结订单号 51 /// </summary> 52 public string ThawOrderNumber { get; set; } 53 54 /// <summary> 55 /// 解冻状态 56 /// </summary> 57 public ThawStatus ThawStatus { get; set; } 58 59 /// <summary> 60 /// 解冻金额 61 /// </summary> 62 public decimal ThawAmount { get; set; } 63 64 /// <summary> 65 /// 备注 66 /// </summary> 67 public string ThawRemark { get; set; } 68 69 /// <summary> 70 /// 修改解冻订单状态 71 /// </summary> 72 /// <param name="freezeStatus">冻结订单状态</param> 73 public void UpdateThawStatus(ThawStatus freezeStatus) 74 { 75 this.ThawStatus = freezeStatus; 76 } 77 78 /// <summary> 79 /// 解冻 80 /// </summary> 81 /// <returns>账单</returns> 82 public ControlBill Thaw() 83 { 84 this.FreezeOrder.Thaw(this.ThawAmount); 85 this.Account.Thaw(this.ThawAmount); 86 this.UpdateThawStatus(ThawStatus.解冻成功); 87 return this.CreateControlBill(); 88 } 89 90 /// <summary> 91 /// The create control bill. 92 /// </summary> 93 /// <returns> 94 /// The <see cref="ControlBill"/>. 95 /// </returns> 96 private ControlBill CreateControlBill() 97 { 98 var bill = new ControlBill 99 { 100 Account = this.Account, 101 Balance = this.Account.Balance, 102 AvailableBalance = this.Account.AvailableBalance, 103 FreezeAmount = this.Account.FreezeAmount, 104 ControlAmount = this.ThawAmount, 105 ControlDateTime = DateTime.Now, 106 ControlOrderNumber = this.ThawOrderNumber, 107 ControlRemark = this.ThawRemark, 108 ControlType = ControlType.Thaw, 109 OrderNumber = Builder.BuilderOrderNumber() 110 }; 111 112 return bill; 113 } 114 }
这样设计出来就简单明了了
1 /// <summary> 2 /// 解冻 3 /// </summary> 4 /// <param name="thawDTO">解冻信息</param> 5 public static void Thaw(ThawDTO thawDTO) 6 { 7 thawDTO.ValidateThawDTO(); 8 FreezeOrder freezeOrder = QueryFreezeOrder(thawDTO.FreezeOrderNumber); 9 ThawOrder thawOrder = Builder.BuilderThawOrder(freezeOrder, thawDTO); 10 ControlBill controlBill = thawOrder.Thaw(); 11 using (IUnitOfWork unitOfWork = Account.Factory.AccountFactory.CreateIUnitOfWork()) 12 { 13 IAccountRepository accountRepository = Account.Factory.AccountFactory.CreateIAccountRepository(unitOfWork); 14 accountRepository.UpdateFreezeAmount(thawOrder.Account); 15 16 // 生成解冻顶 17 IThawOrderRepsoitory thawOrderRepsoitory = Account.Factory.AccountFactory.CreateIThawOrderRepsoitory(unitOfWork); 18 thawOrderRepsoitory.Add(thawOrder); 19 20 // 修改冻结订单 21 IFreezeOrderRepository freezeOrderRepository = Account.Factory.AccountFactory.CreateIFreezeOrderRepository(unitOfWork); 22 freezeOrderRepository.Update(freezeOrder); 23 24 // 生成解冻账单 25 IControlBillRepository controlBillRepository = Account.Factory.AccountFactory.CreateIControlBillRepository(unitOfWork); 26 controlBillRepository.Add(controlBill); 27 28 unitOfWork.Complete(); 29 } 30 }
到此为止 本篇文章也就结束了 。
本文的目的做到了 业务与持久化无关(数据库操作), 做到了 CodeFirst(代码优先)
最后要做的就是根据领域对象去设计数据库就行