OracleContext.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. using Ant.Core;
  2. using Ant.Core.Visitors;
  3. using Ant.Data;
  4. using Ant.DbExpressions;
  5. using Ant.Descriptors;
  6. using Ant.Entity;
  7. using Ant.Exceptions;
  8. using Ant.Infrastructure;
  9. using Ant.ORM;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Linq;
  13. using System.Linq.Expressions;
  14. using System.Reflection;
  15. using System.Text;
  16. namespace Ant.Oracle
  17. {
  18. /// <summary>
  19. /// Oracle数据库
  20. /// </summary>
  21. public class OracleContext : DbContext
  22. {
  23. DbContextServiceProvider _dbContextServiceProvider;
  24. bool _convertToUppercase = true;
  25. /// <summary>
  26. ///
  27. /// </summary>
  28. /// <param name="dbConnectionFactory"></param>
  29. public OracleContext(string dbConnectionFactory)
  30. {
  31. Utils.CheckNull(dbConnectionFactory);
  32. this._dbContextServiceProvider = new DbContextServiceProvider(ConvertToUppercase);
  33. }
  34. /// <summary>
  35. ///
  36. /// </summary>
  37. public bool ConvertToUppercase { get { return this._convertToUppercase; } set { this._convertToUppercase = value; } }
  38. /// <summary>
  39. ///
  40. /// </summary>
  41. public override IDbContextServiceProvider DbContextServiceProvider
  42. {
  43. get { return this._dbContextServiceProvider; }
  44. }
  45. /// <summary>
  46. ///
  47. /// </summary>
  48. /// <typeparam name="T"></typeparam>
  49. /// <param name="entity"></param>
  50. /// <returns></returns>
  51. public override T Insert<T>(T entity)
  52. {
  53. Utils.CheckNull(entity);
  54. TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());
  55. EnsureMappingTypeHasPrimaryKey(typeDescriptor);
  56. MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;
  57. MemberInfo keyMember = typeDescriptor.PrimaryKey.MemberInfo;
  58. object keyValue = null;
  59. string sequenceName;
  60. object sequenceValue = null;
  61. MappingMemberDescriptor defineSequenceMemberDescriptor = GetDefineSequenceMemberDescriptor(typeDescriptor, out sequenceName);
  62. if (defineSequenceMemberDescriptor != null)
  63. {
  64. sequenceValue = ConvertIdentityType(this.GetSequenceNextValue(sequenceName), defineSequenceMemberDescriptor.MemberInfoType);
  65. }
  66. Dictionary<MappingMemberDescriptor, DbExpression> insertColumns = new Dictionary<MappingMemberDescriptor, DbExpression>();
  67. foreach (var kv in typeDescriptor.MappingMemberDescriptors)
  68. {
  69. MemberInfo member = kv.Key;
  70. MappingMemberDescriptor memberDescriptor = kv.Value;
  71. object val = null;
  72. if (defineSequenceMemberDescriptor != null && memberDescriptor == defineSequenceMemberDescriptor)
  73. {
  74. val = sequenceValue;
  75. }
  76. else
  77. val = memberDescriptor.GetValue(entity);
  78. if (memberDescriptor == keyMemberDescriptor)
  79. {
  80. keyValue = val;
  81. }
  82. DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
  83. insertColumns.Add(memberDescriptor, valExp);
  84. }
  85. if (keyValue == null)
  86. {
  87. throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.MemberInfo.Name));
  88. }
  89. DbInsertExpression e = new DbInsertExpression(typeDescriptor.Table);
  90. foreach (var kv in insertColumns)
  91. {
  92. e.InsertColumns.Add(kv.Key.Column, kv.Value);
  93. }
  94. this.ExecuteSqlCommand(e);
  95. if (defineSequenceMemberDescriptor != null)
  96. defineSequenceMemberDescriptor.SetValue(entity, sequenceValue);
  97. return entity;
  98. }
  99. public override object Insert<T>(Expression<Func<T>> body)
  100. {
  101. Utils.CheckNull(body);
  102. TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(T));
  103. EnsureMappingTypeHasPrimaryKey(typeDescriptor);
  104. MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;
  105. string sequenceName;
  106. object sequenceValue = null;
  107. MappingMemberDescriptor defineSequenceMemberDescriptor = GetDefineSequenceMemberDescriptor(typeDescriptor, out sequenceName);
  108. Dictionary<MemberInfo, Expression> insertColumns = InitMemberExtractor.Extract(body);
  109. DbInsertExpression e = new DbInsertExpression(typeDescriptor.Table);
  110. object keyVal = null;
  111. foreach (var kv in insertColumns)
  112. {
  113. MemberInfo key = kv.Key;
  114. MappingMemberDescriptor memberDescriptor = typeDescriptor.TryGetMappingMemberDescriptor(key);
  115. if (memberDescriptor == null)
  116. throw new ChloeException(string.Format("The member '{0}' does not map any column.", key.Name));
  117. if (memberDescriptor == defineSequenceMemberDescriptor)
  118. throw new ChloeException(string.Format("Can not insert value into the column '{0}',because it's mapping member has define a sequence.", memberDescriptor.Column.Name));
  119. if (memberDescriptor.IsPrimaryKey)
  120. {
  121. object val = ExpressionEvaluator.Evaluate(kv.Value);
  122. if (val == null)
  123. throw new ChloeException(string.Format("The primary key '{0}' could not be null.", memberDescriptor.MemberInfo.Name));
  124. else
  125. {
  126. keyVal = val;
  127. e.InsertColumns.Add(memberDescriptor.Column, DbExpression.Parameter(keyVal));
  128. continue;
  129. }
  130. }
  131. e.InsertColumns.Add(memberDescriptor.Column, typeDescriptor.Visitor.Visit(kv.Value));
  132. }
  133. if (keyMemberDescriptor == defineSequenceMemberDescriptor)
  134. {
  135. sequenceValue = ConvertIdentityType(this.GetSequenceNextValue(sequenceName), defineSequenceMemberDescriptor.MemberInfoType);
  136. keyVal = sequenceValue;
  137. e.InsertColumns.Add(keyMemberDescriptor.Column, DbExpression.Parameter(keyVal));
  138. }
  139. if (keyVal == null)
  140. {
  141. throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.MemberInfo.Name));
  142. }
  143. this.ExecuteSqlCommand(e);
  144. return keyVal;
  145. }
  146. public override int Update<T>(T entity)
  147. {
  148. Utils.CheckNull(entity);
  149. TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());
  150. EnsureMappingTypeHasPrimaryKey(typeDescriptor);
  151. MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;
  152. MemberInfo keyMember = keyMemberDescriptor.MemberInfo;
  153. object keyVal = null;
  154. IEntityState entityState = this.TryGetTrackedEntityState(entity);
  155. Dictionary<MappingMemberDescriptor, DbExpression> updateColumns = new Dictionary<MappingMemberDescriptor, DbExpression>();
  156. foreach (var kv in typeDescriptor.MappingMemberDescriptors)
  157. {
  158. MemberInfo member = kv.Key;
  159. MappingMemberDescriptor memberDescriptor = kv.Value;
  160. if (member == keyMember)
  161. {
  162. keyVal = memberDescriptor.GetValue(entity);
  163. keyMemberDescriptor = memberDescriptor;
  164. continue;
  165. }
  166. SequenceAttribute attr = (SequenceAttribute)memberDescriptor.GetCustomAttribute(typeof(SequenceAttribute));
  167. if (attr != null)
  168. continue;
  169. object val = memberDescriptor.GetValue(entity);
  170. if (entityState != null && !entityState.HasChanged(memberDescriptor, val))
  171. continue;
  172. DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
  173. updateColumns.Add(memberDescriptor, valExp);
  174. }
  175. if (keyVal == null)
  176. throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMember.Name));
  177. if (updateColumns.Count == 0)
  178. return 0;
  179. DbExpression left = new DbColumnAccessExpression(typeDescriptor.Table, keyMemberDescriptor.Column);
  180. DbExpression right = DbExpression.Parameter(keyVal, keyMemberDescriptor.MemberInfoType);
  181. DbExpression conditionExp = new DbEqualExpression(left, right);
  182. DbUpdateExpression e = new DbUpdateExpression(typeDescriptor.Table, conditionExp);
  183. foreach (var item in updateColumns)
  184. {
  185. e.UpdateColumns.Add(item.Key.Column, item.Value);
  186. }
  187. int ret = this.ExecuteSqlCommand(e);
  188. if (entityState != null)
  189. entityState.Refresh();
  190. return ret;
  191. }
  192. public override int Update<T>(Expression<Func<T, T>> body, Expression<Func<T, bool>> condition)
  193. {
  194. Utils.CheckNull(body);
  195. Utils.CheckNull(condition);
  196. TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(T));
  197. Dictionary<MemberInfo, Expression> updateColumns = InitMemberExtractor.Extract(body);
  198. DbExpression conditionExp = typeDescriptor.Visitor.VisitFilterPredicate(condition);
  199. DbUpdateExpression e = new DbUpdateExpression(typeDescriptor.Table, conditionExp);
  200. foreach (var kv in updateColumns)
  201. {
  202. MemberInfo key = kv.Key;
  203. MappingMemberDescriptor memberDescriptor = typeDescriptor.TryGetMappingMemberDescriptor(key);
  204. if (memberDescriptor == null)
  205. throw new ChloeException(string.Format("The member '{0}' does not map any column.", key.Name));
  206. if (memberDescriptor.IsPrimaryKey)
  207. throw new ChloeException(string.Format("Could not update the primary key '{0}'.", memberDescriptor.Column.Name));
  208. SequenceAttribute attr = (SequenceAttribute)memberDescriptor.GetCustomAttribute(typeof(SequenceAttribute));
  209. if (attr != null)
  210. throw new ChloeException(string.Format("Could not update the column '{0}',because it's mapping member has define a sequence.", memberDescriptor.Column.Name));
  211. e.UpdateColumns.Add(memberDescriptor.Column, typeDescriptor.Visitor.Visit(kv.Value));
  212. }
  213. if (e.UpdateColumns.Count == 0)
  214. return 0;
  215. return this.ExecuteSqlCommand(e);
  216. }
  217. int ExecuteSqlCommand(DbExpression e)
  218. {
  219. IDbExpressionTranslator translator = this.DbContextServiceProvider.CreateDbExpressionTranslator();
  220. List<DbParam> parameters;
  221. string cmdText = translator.Translate(e, out parameters);
  222. int r = this.db.ExecuteNonQuery(cmdText, parameters.ToArray());
  223. return r;
  224. }
  225. object GetSequenceNextValue(string sequenceName)
  226. {
  227. if (this.ConvertToUppercase)
  228. sequenceName = sequenceName.ToUpper();
  229. object ret = this.db.ExecuteScalar(string.Concat("SELECT \"", sequenceName, "\".\"NEXTVAL\" FROM \"DUAL\""));
  230. if (ret == null || ret == DBNull.Value)
  231. {
  232. throw new ChloeException(string.Format("Unable to get the sequence '{0}' next value.", sequenceName));
  233. }
  234. return ret;
  235. }
  236. /// <summary>
  237. ///
  238. /// </summary>
  239. /// <param name="typeDescriptor"></param>
  240. /// <param name="sequenceName"></param>
  241. /// <returns></returns>
  242. static MappingMemberDescriptor GetDefineSequenceMemberDescriptor(TypeDescriptor typeDescriptor, out string sequenceName)
  243. {
  244. sequenceName = null;
  245. MappingMemberDescriptor defineSequenceMemberDescriptor = null;
  246. foreach (MappingMemberDescriptor memberDescriptor in typeDescriptor.MappingMemberDescriptors.Values)
  247. {
  248. SequenceAttribute attr = (SequenceAttribute)memberDescriptor.GetCustomAttribute(typeof(SequenceAttribute));
  249. if (attr != null)
  250. {
  251. if (defineSequenceMemberDescriptor != null)
  252. {
  253. throw new ChloeException(string.Format("映射类型'{0}'不能确定身份的多个成员。", typeDescriptor.EntityType.FullName));
  254. //throw new ChloeException(string.Format("Mapping type '{0}' can not define multiple identity members.", typeDescriptor.EntityType.FullName));
  255. }
  256. if (string.IsNullOrEmpty(attr.Name))
  257. {
  258. throw new ChloeException("序列名称不能为空。");
  259. //throw new ChloeException("Sequence name can not be empty.");
  260. }
  261. sequenceName = attr.Name;
  262. defineSequenceMemberDescriptor = memberDescriptor;
  263. }
  264. }
  265. if (defineSequenceMemberDescriptor != null)
  266. EnsureDefineSequenceMemberType(defineSequenceMemberDescriptor);
  267. return defineSequenceMemberDescriptor;
  268. }
  269. static void EnsureDefineSequenceMemberType(MappingMemberDescriptor defineSequenceMemberDescriptor)
  270. {
  271. if (defineSequenceMemberDescriptor.MemberInfoType != UtilConstants.TypeOfInt16 && defineSequenceMemberDescriptor.MemberInfoType != UtilConstants.TypeOfInt32 && defineSequenceMemberDescriptor.MemberInfoType != UtilConstants.TypeOfInt64)
  272. {
  273. throw new ChloeException("Identity type must be Int16,Int32 or Int64.");
  274. }
  275. }
  276. static void EnsureMappingTypeHasPrimaryKey(TypeDescriptor typeDescriptor)
  277. {
  278. if (!typeDescriptor.HasPrimaryKey())
  279. throw new ChloeException(string.Format("Mapping type '{0}' does not define a primary key.", typeDescriptor.EntityType.FullName));
  280. }
  281. static object ConvertIdentityType(object identity, Type conversionType)
  282. {
  283. if (identity.GetType() != conversionType)
  284. return Convert.ChangeType(identity, conversionType);
  285. return identity;
  286. }
  287. }
  288. }