您的位置:首页 > 数据库

ORM映射框架总结--SQL 语句生成组件

2011-09-01 12:52 441 查看
1. SQL 语句生成组建
之前说过ORM框架中有一个非常重要的组件,那就是SQL语句生成组件。SQL语句生成组件,顾名思义就是用于生成sql语句的一个组件。之前的Attribute 是用于修饰实体信息,而上一章讲的实体分析器分析了实体信息,在很大一部分程度上,以上做工作就是为这个SQL语句生成组件服务的。

该组件的核心接口是IDbFactory,它实现了接口IDisposable

目前该ORM支持SQL Server 数据库的sql语句生成,在后期过程中会逐步实现对Oracle,Mysql,Access 等数据库的支持

下面是该接口定义的方法图表:


2. 核心接口

核心接口定义源码




核心接口定义源码

1 /**

2 * 2010-2-2

3 *

4 * 情 缘

5 *

6 * IDbFactory 接口实现了IDisposable 接口,实现该

7 * 接口的类可以通过IDisposable 接口来释放对象占用

8 * 的内存。该接口的主要作用适用于根据实体对象来创

9 * 建SQL Server 数据库脚本。ORM 的主要作用是为了

10 * 实现对象化操作数据库,而此操作就是为了实现对象

11 * 化操作和数据库语句操作的过渡

12 *

13 * */

14 using System;

15 using System.Collections.Generic;

16 using System.Linq;

17 using System.Text;

18 using CommonData.Entity;

19 using System.Data;

20 using CommonData.Model.Core;

21

22 namespace CommonData.Data.Core

23 {

24 public interface IDbFactory : IDisposable

25 {

26 /// <summary>

27 /// 根据实体对象公共接口创建插入的sql语句

28 /// </summary>

29 /// <param name="entity">实体公共接口</param>

30 /// <param name="param">创建sql语句对应占位符参数</param>

31 /// <returns></returns>

32 string CreateInsertSql(IEntity entity, out IDataParameter[] param);

33

34 /// <summary>

35 /// 根据实体类型创建插入sql语句

36 /// </summary>

37 /// <param name="type">实体类型</param>

38 /// <param name="value">实体对象</param>

39 /// <param name="param">创建sql语句对应占位符参数</param>

40 /// <returns></returns>

41 string CreateInsertSql(Type type, object value, out IDataParameter[] param);

42

43 /// <summary>

44 /// 根据泛型类型创建插入sql语句

45 /// </summary>

46 /// <typeparam name="T">泛型类型</typeparam>

47 /// <param name="t">泛型实体类</param>

48 /// <param name="param">创建sql语句对应占位符参数</param>

49 /// <returns></returns>

50 string CreateInsertSql<T>(T t, out IDataParameter[] param) where T : IEntity;

51

52 /// <summary>

53 /// 根据实体对象公共接口创建修改的的sql语句

54 /// 该sql语句是根据主键列修改的

55 /// </summary>

56 /// <param name="entity">实体公共接口</param>

57 /// <param name="param">创建sql语句对应占位符参数</param>

58 /// <returns></returns>

59 string CreateUpdateSql(IEntity entity, out IDataParameter[] param);

60

61 /// <summary>

62 /// 根据实体对象类型创建修改的的sql语句

63 /// </summary>

64 /// <param name="type">实体类型</param>

65 /// <param name="value">实体对象</param>

66 /// <param name="param">创建sql语句对应占位符参数</param>

67 /// <returns></returns>

68 string CreateUpdateSql(Type type, object value, out IDataParameter[] param);

69

70 /// <summary>

71 /// 根据实体对象公共接口创建修改的的sql语句

72 /// 该sql语句是根据一个特定的属性作为修改条件的

73 /// </summary>

74 /// <param name="entity">实体公共接口</param>

75 /// <param name="param">创建sql语句对应占位符参数</param>

76 /// <param name="propertyName">属性名称</param>

77 /// <returns></returns>

78 string CreateUpdateSql(IEntity entity, out IDataParameter[] param, string propertyName);

79

80 /// <summary>

81 /// 根据实体对象类型创建修改的的sql语句

82 /// 该sql语句是根据一个特定的属性作为修改条件的

83 /// </summary>

84 /// <param name="type">实体类型</param>

85 /// <param name="value">实体对象</param>

86 /// <param name="param">创建sql语句对应占位符参数</param>

87 /// <param name="propertyName">属性名称</param>

88 /// <returns></returns>

89 string CreateUpdateSql(Type type, object value, out IDataParameter[] param, string propertyName);

90

91 /// <summary>

92 /// 根据实体对象公共接口创建修改的的sql语句

93 /// 该sql语句是根据多个特定的属性作为修改条件的

94 /// </summary>

95 /// <param name="entity">实体公共接口</param>

96 /// <param name="param">创建sql语句对应占位符参数</param>

97 /// <param name="propertyNames">属性名称</param>

98 /// <returns></returns>

99 string CreateUpdateSql(IEntity entity, out IDataParameter[] param, string[] propertyNames);

100

101 /// <summary>

102 /// 根据实体对象类型创建修改的的sql语句

103 /// 该sql语句是根据多个特定的属性作为修改条件的

104 /// </summary>

105 /// <param name="type">实体类型</param>

106 /// <param name="value">实体对象</param>

107 /// <param name="param">创建sql语句对应占位符参数</param>

108 /// <param name="propertyNames">属性名称</param>

109 /// <returns></returns>

110 string CreateUpdateSql(Type type, object value, out IDataParameter[] param, string[] propertyNames);

111

112 /// <summary>

113 /// 根据实体对象公共接口创建修改的的sql语句

114 /// 该sql语句是根据查询组建创建的

115 /// </summary>

116 /// <param name="entity">实体公共接口</param>

117 /// <param name="param">创建sql语句对应占位符参数</param>

118 /// <param name="component">查询条件组件</param>

119 /// <returns></returns>

120 string CreateUpdateSql(IEntity entity, out IDataParameter[] param, ConditionComponent component);

121

122 /// <summary>

123 /// 根据实体对象公共接口创建删除sql语句

124 /// 该sql语句是根据实体主键删除

125 /// </summary>

126 /// <param name="entity">实体公共接口</param>

127 /// <param name="param">创建sql语句对应占位符参数</param>

128 /// <returns></returns>

129 string CreateDeleteSql(IEntity entity, out IDataParameter[] param);

130

131 /// <summary>

132 /// 根据实体对象类型创建删除sql语句

133 /// 该sql语句是根据实体主键删除

134 /// </summary>

135 /// <param name="type">实体类型</param>

136 /// <param name="value">实体对象</param>

137 /// <param name="param">创建sql语句对应占位符参数</param>

138 /// <returns></returns>

139 string CreateDeleteSql(Type type,object value,out IDataParameter[] param);

140

141 /// <summary>

142 /// 根据实体对象公共接口的某个属性创建删除sql语句

143 /// 该sql语句是根据实体属性删除

144 /// </summary>

145 /// <param name="entity">实体公共接口</param>

146 /// <param name="param">创建sql语句对应占位符参数</param>

147 /// <param name="propertyName">实体属性名称</param>

148 /// <returns></returns>

149 string CreateDeleteSql(IEntity entity, out IDataParameter[] param, string propertyName);

150

151 /// <summary>

152 /// 根据实体对象类型的某个属性创建删除sql语句

153 /// 该sql语句是根据实体属性删除

154 /// </summary>

155 /// <param name="type">实体类型</param>

156 /// <param name="value">实体对象</param>

157 /// <param name="param">创建sql语句对应占位符参数</param>

158 /// <param name="propertyName">实体属性名称</param>

159 /// <returns></returns>

160 string CreateDeleteSql(Type type, object value, out IDataParameter[] param, string propertyName);

161

162 /// <summary>

163 /// 根据实体对象公共接口的多个属性创建删除sql语句

164 /// 该sql语句是根据实体多个属性删除

165 /// </summary>

166 /// <param name="entity">实体公共接口</param>

167 /// <param name="param">创建sql语句对应占位符参数</param>

168 /// <param name="propertyName">实体属性名称数组</param>

169 /// <returns></returns>

170 string CreateDeleteSql(IEntity entity, out IDataParameter[] param, string[] propertyNames);

171

172 /// <summary>

173 /// 根据实体对象类型的多个属性创建删除sql语句

174 /// 该sql语句是根据实体多个属性删除

175 /// </summary>

176 /// <param name="type">实体了姓</param>

177 /// <param name="value">实体对象</param>

178 /// <param name="param">创建sql语句对应占位符参数</param>

179 /// <param name="propertyNames">实体属性名称数组</param>

180 /// <returns></returns>

181 string CreateDeleteSql(Type type, object value, out IDataParameter[] param, string[] propertyNames);

182

183 /// <summary>

184 /// 根据实体对象公共接口的多个属性创建删除sql语句

185 /// 该sql语句使根据查询组建来创建的

186 /// </summary>

187 /// <param name="entity">实体公共接口</param>

188 /// <param name="param">创建sql语句对应占位符参数</param>

189 /// <param name="component">实体属性名称数组</param>

190 /// <returns></returns>

191 string CreateDeleteSql(IEntity entity, out IDataParameter[] param, ConditionComponent component);

192

193 /// <summary>

194 /// 根据实体的公共接口创建查询单行数据的sql语句

195 /// 该sql语句是根据数据库表的主键来查询的

196 /// </summary>

197 /// <param name="entity">实体公共接口</param>

198 /// <param name="param">创建sql语句对应占位符参数</param>

199 /// <returns></returns>

200 string CreateSingleSql(IEntity entity, out IDataParameter[] param);

201

202 /// <summary>

203 /// 根据实体的公共接口创建查询单行数据的sql语句

204 /// 该sql语句是根据实体的相应属性来查询

205 /// </summary>

206 /// <param name="entity">实体公共接口</param>

207 /// <param name="param">创建sql语句对应占位符参数</param>

208 /// <returns></returns>

209 string CreateSingleSql(IEntity entity, out IDataParameter[] param, string[] propertyNames);

210

211 /// <summary>

212 /// 根据实体类型创建查询单行数据的sql语句

213 /// 该sql语句是根据实体的相应属性来查询

214 /// </summary>

215 /// <param name="type">实体类型</param>

216 /// <param name="value">实体对象</param>

217 /// <param name="param">创建sql语句对应占位符参数</param>

218 /// <param name="propertyNames">属性名称数组</param>

219 /// <returns></returns>

220 string CreateSingleSql(Type type, object value, out IDataParameter[] param, string[] propertyNames);

221

222 /// <summary>

223 /// 根据实体的类型创建查询sql语句

224 /// </summary>

225 /// <param name="entityType">实体类型</param>

226 /// <returns></returns>

227 string CreateSingleSql(Type entityType);

228

229 /// <summary>

230 /// 根据实体的类型创建查询sql语句,

231 /// 该方法指定主键值

232 /// </summary>

233 /// <param name="type">实体类型</param>

234 /// <param name="pkPropertyValue">主键值</param>

235 /// <param name="param">创建sql语句对应占位符参数</param>

236 /// <returns></returns>

237 string CreateSingleSql(Type type, object pkPropertyValue,out IDataParameter[] param);

238

239 /// <summary>

240 /// 根据实体的类型创建查询该实体对象对应数据库表的所有数据的sql语句

241 /// 该sql语句用于查询所有数据,并转换为相应List<T> 集合

242 /// </summary>

243 /// <param name="type">实体的类型</param>

244 /// <returns></returns>

245 string CreateQuerySql(Type type);

246

247 /// <summary>

248 /// 根据实体的某个属性创建根据该属性字段查询数据的sql语句

249 /// 该sql语句是使用参数中属性对应字段作为条件查询的

250 /// </summary>

251 /// <param name="type">实体类型</param>

252 /// <param name="propertyName">属性名称</param>

253 /// <param name="value">属性值</param>

254 /// <param name="param">sql语句占位符参数</param>

255 /// <returns></returns>

256 string CreateQueryByPropertySql(Type type, string propertyName, object value, out IDataParameter[] param);

257

258 /// <summary>

259 /// 根据实体的某些属性创建根据该些属性字段查询数据的sql语句

260 /// 该sql语句是使用参数中属性对应字段作为条件查询的,并且该

261 /// 属性集合都是根据and条件组装的

262 /// </summary>

263 /// <param name="type">实体类型</param>

264 /// <param name="dic">属性-值集合</param>

265 /// <param name="param">sql语句占位符参数</param>

266 /// <returns></returns>

267 string CreateQueryByPropertySql(Type type, IDictionary<string, object> dic, out IDataParameter[] param);

268

269 /// <summary>

270 /// 根据实体的某些属性创建根据该些属性字段查询数据的sql语句

271 /// 该sql语句是使用参数中属性对应字段作为条件查询的,并且查

272 /// 询是根据查询组建来创建

273 /// </summary>

274 /// <param name="type">实体类型</param>

275 /// <param name="dic">属性-值集合</param>

276 /// <param name="param">sql语句占位符参数</param>

277 /// <param name="component">查询组建</param>

278 /// <returns></returns>

279 string CreateQueryByPropertySql(Type type, IDictionary<string, object> dic, out IDataParameter[] param, ConditionComponent component);

280

281 /// <summary>

282 /// 根据实体类型来创建该实体对应数据库表的聚合函数查询sql语句

283 /// 该方法创建的sql语句主要是用于查询数据行数

284 /// </summary>

285 /// <param name="type">实体类型</param>

286 /// <param name="converage">聚合函数枚举类型</param>

287 /// <returns></returns>

288 string CreateConverageSql(Type type, Converage converage);

289

290 /// <summary>

291 /// 根据实体类型来创建该实体对应数据库表的聚合函数查询sql语句

292 /// 该方法创建的sql语句主要是用于统计查询(最大值,最小值,求和,平均值,数据行数)

293 /// </summary>

294 /// <param name="type">实体类型</param>

295 /// <param name="converage">聚合函数枚举类型</param>

296 /// <param name="propertyName">聚合函数作用的属性名称</param>

297 /// <returns></returns>

298 string CreateConverageSql(Type type, Converage converage, string propertyName);

299

300 /// <summary>

301 /// 根据实体类型来创建该实体对应数据库表的聚合函数查询sql语句

302 /// 该方法创建的sql语句主要是用于统计查询(最大值,最小值,求和,平均值,数据行数),

303 /// 同时该sql是有条件查询的

304 /// </summary>

305 /// <param name="type">实体类型</param>

306 /// <param name="converage">聚合函数枚举类型</param>

307 /// <param name="propertyName">聚合函数作用的属性名称</param>

308 /// <param name="dic">查询条件属性键值</param>

309 /// <param name="component">查询条件组建对象</param>

310 /// <returns></returns>

311 string CreateConverageSql(Type type, Converage converage, string propertyName, IDictionary<string, object> dic, out IDataParameter[] param, ConditionComponent component);

312

313 /// <summary>

314 /// 根据占位符名称创建参数

315 /// </summary>

316 /// <param name="name">占位符名称</param>

317 /// <returns></returns>

318 IDataParameter CreateParameter(string name);

319

320 /// <summary>

321 /// 根据占位符和值创建参数

322 /// </summary>

323 /// <param name="name">占位符名称</param>

324 /// <param name="value">占位符的值</param>

325 /// <returns></returns>

326 IDataParameter CreateParameter(string name, object value);

327

328 /// <summary>

329 /// 根据占位符名称,类型和值创建参数

330 /// </summary>

331 /// <param name="name">占位符名称</param>

332 /// <param name="type">参数的类型</param>

333 /// <param name="value">参数的值</param>

334 /// <returns></returns>

335 IDataParameter CreateParameter(string name, DataType type, object value);

336

337 /// <summary>

338 /// 根据占位符的名称,类型和大小创建参数

339 /// </summary>

340 /// <param name="name">占位符名称</param>

341 /// <param name="type">参数类型</param>

342 /// <param name="size">参数值大小</param>

343 /// <returns></returns>

344 IDataParameter CreateParameter(string name, DataType type, int size);

345

346 /// <summary>

347 /// 根据占位符的名称,类型,大小和值创建参数

348 /// </summary>

349 /// <param name="name">占位符名称</param>

350 /// <param name="type">参数类型</param>

351 /// <param name="size">参数大小</param>

352 /// <param name="value">参数值</param>

353 /// <returns></returns>

354 IDataParameter CreateParameter(string name, DataType type, int size, object value);

355

356 /// <summary>

357 /// 根据占位符名称和类型创建参数

358 /// </summary>

359 /// <param name="name">占位符名称</param>

360 /// <param name="type">占位符类型</param>

361 /// <returns></returns>

362 IDataParameter CreateParameter(string name, DataType type);

363 }

364 }

365

该接口定了生成增删改查等sql语句的方法

CreateInsertSql() 方法主要用于生成插入语句,该方法被重载了3次,根据各种不同的情况来生成数据库插入sql语句。

CreateUpdateSql() 方法主要用于生成修改语句,该方法被重载了7次,根据各种不同的情况来生成数据的修改sql语句。

CreateDeleteSql() 方法主要用于生成删除语句,该方法同样被重载了7次,根据各种不同的情况来生成数据库的删除sql语句。

CreateSingleSql() 方法主要用于生成查询单个实体的sql语句,该方法被重载了5次,根据各种不同的情况来生成数据库的单数据行sql语句。

CreateQuerySql() 方法主要用于生成查询集合的sql语句,该方法只被重载了一次,从上面的源码中可以看出,该方法只有一个Type类型参数,此方法不做正在意义上查询使用,此方法在配合级联查询的时候能够起到重要的作用。

CreateQueryByPropertySql() 方法主要生成条件查询的sql语句,该方法被充值了3次,根据不同的情况来生成数据的集合查询的sql语句。注意该方法中引入了一个新的对象ConditionComponent,在后面的说明中对次类进行讲解。

CreateConverageSql() 方法主要用于生成查询聚合函数的sql语句,该方法同样被重载了3次,根据不同的情况来生成查询聚合函数的sql语句。该方法同样也引入了一个新的对象Converage,在后面的说明中对次类进行讲解。

CreateParameter() 方法主要用于生成sql语句占位符参数的,该方法被重载了6次。

以上是该核心接口定义的几组方法,用于生成sql语句。在程序设计的过程中,都采用的面向接口来编程,目前来说只支持sql server 数据的sql语句生成,但是考虑到后期的补充,觉得在使用接口编程就尤为重要。后期的工作就是根据不同的数据库去实现该接口中的所有方法。

3. 插入sql语句的生成

上面说到了插入sql语句被重载了3次,在很多情况下我们根据情况的不同生成sql语句所需的方式也不同,于是归纳成了三个重载方法,该三个重载放一般情况下是可以覆盖所有的生成插入语句的情况。

string CreateInsertSql(IEntity entity, out IDataParameter[] param);

在上面的桥梁映射过程中,我们提到了一个接口IEntity,它是所有实体的父级接口,该接口并未定义任何方法,或许当时有人认为这是多此一举,不过现在大家应该明白了,这样定义是有缘由的。因为这个插入语句的生成要覆盖所有的实体类,于是我们必须抽象出来,抽象它们共同拥有的特性。在这里,这个IEntity 接口的重要性显得尤为突出。Param参数这是用于存储sql语句的占位符的,看到这个参数的修饰符out,说明参数传入本身是空的,也就是说在后期的实现过程中我们要动态的去给param赋值,参数名,参数值,以及数组的长度都是由entity
来决定。

string CreateInsertSql(Type type, object value, out IDataParameter[] param);

说到重载,这是面向对象编程的四要素之一,多态表现形式之一,另外一种是重写。重载其实要实现的功能是一样,只是表现形式不同而已,这里使用了Type,这里就是要插入的实体的类型,后面的object value 就是实体,紧接着的参数就不用多说了,上面的方法已经提到过。

string CreateInsertSql<T>(T t, out IDataParameter[] param) where T : IEntity

说到这个重载方法,大家一般都会很兴奋,为什么.我第一眼看到了<T> ,.net中的泛型。.net中的泛型我可以说真的是无懈可击,那各种形态的使用方式是如此的婀娜多姿,总是让程序员沉迷于其中的美妙,最起码我是这样的。后面的where T : IEntity 就是泛型约束了,泛型约束可以让我们的程序减少很多不必要的麻烦。因为泛型本身就是一种不确定的类型,我们规定了他使用的范围,这样能够减少它出错的可能性。

下面看看这个插入sql的生成核心代码:




插入sql的生成核心代码

1 /// <summary>

2 /// 根据实体类型创建插入sql语句

3 /// </summary>

4 /// <param name="type">实体类型</param>

5 /// <param name="value">实体对象</param>

6 /// <param name="param">创建sql语句对应占位符参数</param>

7 /// <returns></returns>

8 public string CreateInsertSql(Type type, object value, out IDataParameter[] param)

9 {

10 if (value == null)

11 {

12 throw new NullReferenceException("the save entity is null");

13 }

14 StringBuilder sbColumn = new StringBuilder("");

15 StringBuilder sbValues = new StringBuilder("");

16 IDictionary<string, ColumnAttribute> dicColumn = EntityTypeCache.GetTableInfo(type).DicColumns;

17 if (dicColumn.Keys.Count > 0)

18 {

19 sbColumn.AppendFormat("insert into {0} (", EntityTypeCache.GetTableInfo(type).Table.Name);

20 sbValues.AppendFormat(" values (");

21 IList<IDataParameter> listParams = new List<IDataParameter>();

22 foreach (string key in dicColumn.Keys)

23 {

24 if (!dicColumn[key].AutoIncrement)

25 {

26 sbColumn.AppendFormat("{0},", dicColumn[key].Name);

27 sbValues.AppendFormat("{0},", "@" + dicColumn[key].Name);

28 }

29 if (EntityFactory.GetPropertyValue(value, key) == null)

30 {

31 listParams.Add(CreateParameter("@" + key, System.DBNull.Value));

32 }

33 else

34 {

35 listParams.Add(CreateParameter("@" + key, EntityFactory.GetPropertyValue(value, key)));

36 }

37 }

38 sbColumn.Replace(",", ")", sbColumn.Length - 1, 1);

39 sbValues.Replace(",", ")", sbValues.Length - 1, 1);

40 param = listParams.ToArray();

41 return sbColumn.ToString() + sbValues.ToString();

42 }

43 else

44 {

45 param = null;

46 return null;

47 }

48 }

当大家看到这里肯定也觉得,原理这个东西也不过如此。如果真是这样,那我也就替你高兴了,因为我要传达的意思你已经明白了,也就是说我写这边博文的传达的信息你收到了。一次完美的会话完成。

StringBuilder sbColumn = new StringBuilder("");
StringBuilder sbValues = new StringBuilder("");

代码中定义了这两个类,不使用string的原因大家也知道。还有这里我们生成sql语句的规则就是sql语句插入的语法规则,这里不再多说。

4. 修改sql语句

生成修改sql语句的方法CreateUpdateSql()被重载了七次,其实生成sql语句的原理和上面生成插入sql语句的原理是一样的。关键在于如何去抽象一个多情况下处理方式。

string CreateUpdateSql(IEntity entity, out IDataParameter[] param);

这个方法主要是根据实体的主键作为条件来修改

string CreateUpdateSql(IEntity entity, out IDataParameter[] param, string[] propertyNames);

这个方法则是根据实体的过个属性来修改,各个条件以and方式来连接生成sql语句。在生成sql语句的过程中IEntity 必须包含这些数据,而且这些属性值必须存在,否则会抛出异常。与此类似的方法还有只有一个属性名来修改的,其实这个方法可以包括只有一个属性的修改方法,而这里重载一次就是为了使用方便。

string CreateUpdateSql(IEntity entity, out IDataParameter[] param, ConditionComponent component);

这里我们不介绍其他东西了,主要看看ConditionComponent这个类。上面提到过如果多条件修改sql语句,各个属性都是通过and来连接的,如果我们修改使用 or 或者其他的方式怎么办,ConditionComponent可以用来解决此问题。

首先看看这个类的源码:




查询组件存储器源码

1 /**

2 * 2010-3-1

3 *

4 * 情 缘

5 *

6 * 该类封装修改数据,条件查询数据的相关条件。

7 *

8 * */

9 using System;

10 using System.Collections.Generic;

11 using System.Linq;

12 using System.Text;

13

14 namespace CommonData.Model.Core

15 {

16 public class ConditionComponent

17 {

18 private IDictionary<string, SearchComponent> dicComponent = null;

19

20 /// <summary>

21 /// 用于存储属性查询类型

22 /// </summary>

23 public IDictionary<string, SearchComponent> DicComponent

24 {

25 get { return dicComponent; }

26 set { dicComponent = value; }

27 }

28

29 private static ConditionComponent component;

30

31 /// <summary>

32 /// 私有构造方法,禁止外部类构造此类的实例

33 /// 使用私有构造方式主要实现单例模式

34 /// </summary>

35 private ConditionComponent()

36 {

37

38 }

39

40 /// <summary>

41 /// 构造ConditionComponent的实例,当实例不存在是则创建该对象

42 /// 这个是单例模式的实现

43 /// </summary>

44 /// <returns></returns>

45 public static ConditionComponent Instance()

46 {

47 if (component == null)

48 {

49 component = new ConditionComponent();

50 component.DicComponent = new Dictionary<string, SearchComponent>();

51 }

52 return component;

53 }

54

55 /// <summary>

56 /// 添加属性查询类型

57 /// </summary>

58 /// <param name="propertyName">属性名称</param>

59 /// <param name="component">查询类型</param>

60 /// <returns></returns>

61 public ConditionComponent AddComponent(string propertyName,SearchComponent component)

62 {

63 if (component == null)

64 {

65 ConditionComponent.component = Instance();

66 }

67 ConditionComponent.component.DicComponent.Add(propertyName, component);

68 return ConditionComponent.component;

69 }

70

71 }

72 }

73

这个类其实就相当于一个存储器。

private IDictionary<string, SearchComponent> dicComponent = null;

而dicComponent就是用于存储相应的数据的,而且是以键值对的方式存储,这样便于后面使用过程中的查找。而这里又出现了一个心得类SearchComponent,这个是查询条件组建。下面在讲解。这里定义了这个类的一个单例模式,也就是说只能允许一个对象的存在每次。我需要在每次天际参数的同时这个对象仍然存在,并且保存信息。

public ConditionComponent AddComponent(string propertyName,SearchComponent component)
{
if (component == null)
{
ConditionComponent.component = Instance();
}
ConditionComponent.component.DicComponent.Add(propertyName, component);
return ConditionComponent.component;
}

这个方法每次给ConditionComponent添加一个参数,然后又返回这个对象。

下面看看上面的提到的SearchComponent源码:




查询组件枚举

1 /**

2 * 2010-3-1

3 *

4 * 情 缘

5 *

6 * 该类是一个枚举类型,定义了元素查询条件。

7 * 该枚举值都一一对应数据库中的各种查询条

8 * 件。

9 *

10 * */

11 using System;

12 using System.Collections.Generic;

13 using System.Linq;

14 using System.Text;

15

16 namespace CommonData.Model.Core

17 {

18 public enum SearchComponent

19 {

20 /// <summary>

21 /// 对应数据库中的 "="

22 /// </summary>

23 Equals,

24

25 /// <summary>

26 /// 对应数据库中的 "!="

27 /// </summary>

28 UnEquals,

29

30 /// <summary>

31 /// 对应数据库中的 ">"

32 /// </summary>

33 Greater,

34

35 /// <summary>

36 /// 对应数据库中的 ">="

37 /// </summary>

38 GreaterOrEquals,

39

40 /// <summary>

41 /// 对应数据库中的 "<"

42 /// </summary>

43 Less,

44

45 /// <summary>

46 /// 对应数据库中的 "<="

47 /// </summary>

48 LessOrEquals,

49

50 /// <summary>

51 /// 对应数据库中的 "like"

52 /// </summary>

53 Like,

54

55 /// <summary>

56 /// 对应数据库中的 "in"

57 /// </summary>

58 In,

59

60 /// <summary>

61 /// 对应数据库中的 "between and"

62 /// </summary>

63 Between,

64

65 /// <summary>

66 /// 对应数据库中的 "order by asc"

67 /// </summary>

68 OrderAsc,

69

70 /// <summary>

71 /// 对应数据库中的 "order by desc"

72 /// </summary>

73 OrderDesc,

74

75 /// <summary>

76 /// 对应数据库中的 "group by"

77 /// </summary>

78 GroupBy,

79

80 /// <summary>

81 /// 对应数据库中的 "or"

82 /// </summary>

83 Or

84 }

85 }

86

这里的代码大家一看也就明白了,为什么叫查询组件了,它其实就是封装了一些查询可能出现的情况。代码非常简单,这里不再过多讲解。

下面是生成修改语句的方法实现,这个方法的代码包含了查询组件的运用:




修改sql语句的实现

1 /// <summary>

2 /// 根据实体对象公共接口创建修改的的sql语句

3 /// 该sql语句是根据查询组建创建的

4 /// </summary>

5 /// <param name="entity">实体公共接口</param>

6 /// <param name="param">创建sql语句对应占位符参数</param>

7 /// <param name="component">查询条件组件</param>

8 /// <returns></returns>

9 public string CreateUpdateSql(IEntity entity, out IDataParameter[] param, ConditionComponent component)

10 {

11

12 StringBuilder sbColumn = new StringBuilder("");

13 StringBuilder sbValues = new StringBuilder("");

14 IList<IDataParameter> listParams = new List<IDataParameter>();

15 sbColumn.AppendFormat("update {0} set ", EntityTypeCache.GetTableInfo(entity).Table.Name);

16 sbValues.Append(" where 1=1 ");

17 foreach (string propertyName in EntityTypeCache.GetTableInfo(entity).DicProperties.Keys)

18 {

19 //包含则作为条件

20 if (component.DicComponent.Keys.Contains(propertyName))

21 {

22 switch (component.DicComponent[propertyName])

23 {

24 case SearchComponent.Equals:

25 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name, "=", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name);

26 break;

27 case SearchComponent.UnEquals:

28 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name, "!=", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name);

29 break;

30 case SearchComponent.Between:

31 break;

32 case SearchComponent.Greater:

33 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name, ">", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name);

34 break;

35 case SearchComponent.GreaterOrEquals:

36 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name, ">=", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name);

37 break;

38 case SearchComponent.GroupBy:

39 break;

40 case SearchComponent.In:

41 break;

42 case SearchComponent.Less:

43 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name, "<", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name);

44 break;

45 case SearchComponent.LessOrEquals:

46 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name, "<=", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name);

47 break;

48 case SearchComponent.Like:

49 break;

50 case SearchComponent.Or:

51 break;

52 case SearchComponent.OrderAsc:

53 break;

54 case SearchComponent.OrderDesc:

55 break;

56 }

57 listParams.Add(CreateParameter("@" + EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name, EntityFactory.GetPropertyValue(entity, propertyName) == null ? DBNull.Value : EntityFactory.GetPropertyValue(entity, propertyName)));

58 }

59 else //判断主键和唯一列,主键和唯一列不能被修改

60 {

61 if (EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].IsPrimaryKey ||

62 EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].IsUnique ||

63 EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].AutoIncrement)

64 {

65

66 }

67 else

68 {

69 sbColumn.AppendFormat("{0}=@{1},", EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name, EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name);

70 listParams.Add(CreateParameter("@" + EntityTypeCache.GetTableInfo(entity).DicColumns[propertyName].Name, EntityFactory.GetPropertyValue(entity, propertyName) == null ? DBNull.Value : EntityFactory.GetPropertyValue(entity, propertyName)));

71 }

72 }

73 }

74 sbColumn.Remove(sbColumn.Length - 1, 1);

75 param = listParams.ToArray();

76 return sbColumn.ToString() + sbValues.ToString();

77 }

5. 聚合函数的使用

这里不做过多的降解了,都是前篇一律的,不过有个特殊的地方,那就是刚才提到过来的Converage。

先看看这个枚举的源码:




聚合函数Converage枚举

1 /**

2 * 2010-2-26

3 *

4 * 情 缘

5 *

6 * 该类是一个枚举类型,定义了数据库聚合函数

7 * 操作的各种情况。该枚举值可以在使用时候来

8 * 区分sql执行那个聚合函数

9 *

10 * */

11 using System;

12 using System.Collections.Generic;

13 using System.Linq;

14 using System.Text;

15

16 namespace CommonData.Model.Core

17 {

18 public enum Converage

19 {

20 /// <summary>

21 /// 聚合函数取最小值

22 /// </summary>

23 Min,

24

25 /// <summary>

26 /// 聚合函数取最大值

27 /// </summary>

28 Max,

29

30 /// <summary>

31 /// 聚合函数取和

32 /// </summary>

33 Sum,

34

35 /// <summary>

36 /// 聚合函数取所有数据行

37 /// </summary>

38 Count,

39

40 /// <summary>

41 /// 聚合函数取所有非空数据行

42 /// </summary>

43 CountNotNll,

44

45 /// <summary>

46 /// 聚合函数取平均值

47 /// </summary>

48 Avg,

49 }

50 }

51

该代码中定义了最和函数取最大值和最小值,聚合函数求和,聚合函数查询行数,聚合函数求平均值。

下面是聚合函数sql语句生成的代码实现:




聚合函数sql语句生成的代码实现

1 /// <summary>

2 /// 根据实体类型来创建该实体对应数据库表的聚合函数查询sql语句

3 /// 该方法创建的sql语句主要是用于统计查询(最大值,最小值,求和,平均值,数据行数),

4 /// 同时该sql是有条件查询的

5 /// </summary>

6 /// <param name="type">实体类型</param>

7 /// <param name="converage">聚合函数枚举类型</param>

8 /// <param name="propertyName">聚合函数作用的属性名称</param>

9 /// <param name="dic">查询条件属性键值</param>

10 /// <param name="component">查询条件组建对象</param>

11 /// <returns></returns>

12 public string CreateConverageSql(Type type, Converage converage, string propertyName, IDictionary<string, object> dic, out IDataParameter[] param, ConditionComponent component)

13 {

14 StringBuilder sbValues = new StringBuilder();

15 if (string.IsNullOrEmpty(propertyName))

16 {

17 converage = Converage.Count;

18 }

19 if (Converage.Avg == converage)

20 {

21 sbValues.AppendFormat("select avg({0}) from {1} where 1=1 ", EntityTypeCache.GetTableInfo(type).DicColumns[propertyName].Name, EntityTypeCache.GetTableInfo(type).Table.Name);

22 }

23 else if (Converage.Max == converage)

24 {

25 sbValues.AppendFormat("select max({0}) from {1} where 1=1 ", EntityTypeCache.GetTableInfo(type).DicColumns[propertyName].Name, EntityTypeCache.GetTableInfo(type).Table.Name);

26 }

27 else if (Converage.Min == converage)

28 {

29 sbValues.AppendFormat("select min({0}) from {1} where 1=1 ", EntityTypeCache.GetTableInfo(type).DicColumns[propertyName].Name, EntityTypeCache.GetTableInfo(type).Table.Name);

30 }

31 else

32 {

33 sbValues.AppendFormat("select count(*) from {0} where 1=1 ", EntityTypeCache.GetTableInfo(type).Table.Name);

34 }

35

36 IList<IDataParameter> listParams = new List<IDataParameter>();

37 foreach (string key in dic.Keys)

38 {

39 switch (component.DicComponent[key])

40 {

41 case SearchComponent.Equals:

42 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name, "=", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name);

43 break;

44 case SearchComponent.UnEquals:

45 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name, "!=", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name);

46 break;

47 case SearchComponent.Between:

48 break;

49 case SearchComponent.Greater:

50 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name, ">", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name);

51 break;

52 case SearchComponent.GreaterOrEquals:

53 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name, ">=", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name);

54 break;

55 case SearchComponent.GroupBy:

56 break;

57 case SearchComponent.In:

58 break;

59 case SearchComponent.Less:

60 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name, "<", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name);

61 break;

62 case SearchComponent.LessOrEquals:

63 sbValues.AppendFormat("and {0}{1}@{2} ", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name, "<=", EntityTypeCache.GetTableInfo(type).DicColumns[key].Name);

64 break;

65 case SearchComponent.Like:

66 break;

67 case SearchComponent.Or:

68 break;

69 case SearchComponent.OrderAsc:

70 break;

71 case SearchComponent.OrderDesc:

72 break;

73 }

74 listParams.Add(CreateParameter("@" + EntityTypeCache.GetTableInfo(type).DicColumns[key].Name, dic[key]));

75 }

76 param = listParams.ToArray();

77 return sbValues.ToString();

78 }

6. 参数占位符

在这个生成sql语句的组建方法中,我们不断使用了IDataParameter 这个对象,这个对象或许我们看了很陌生,我们用得非常少.(纠正一下是接口),在查询sql Server 数据的时候我们经常使用的一个类 SqlParameter,看到这两个名称如此相似,我们应该也想到了他们是什么关系。因为我们不确定是使用什么数据库,可能是Sql Server,可能是Oracle,还有肯能是Access,所以使用IDataParameter 是比较保险的一种方式。在这个方法中我们也看到了一个新的类型—DataType,它定义了数据库中常用25中类型于.net中数据类型的对应列表。

下面是源码解析:




数据类型对应枚举列表

1 /**

2 * 2010-1-28

3 *

4 * 情 缘

5 *

6 * 用于描述SQL数据库类型和.NET 中数据类型的转化关系

7 * 注意: 这里的数据类型并不是所有的都能直接转化,有

8 * 时候需要通过特定的规则进行强制性转化。这里描述的

9 * 都是SQL Server 数据的类型。

10 * */

11

12 using System;

13

14

15 namespace CommonData.Model.Core

16 {

17 public enum DataType

18 {

19 /// <summary>

20 /// 对应.NET中的数据类型 Int64

21 /// </summary>

22 Bigint,

23

24 /// <summary>

25 /// 对应.NET中的数据类型 Int32

26 /// </summary>

27 Int,

28

29 /// <summary>

30 /// 对应.NET中的数据类型 Int16

31 /// </summary>

32 Smallint,

33

34 /// <summary>

35 /// 对应.NET中的数据类型 System.Byte

36 /// </summary>

37 Tinyint,

38

39 /// <summary>

40 /// 对应.NET中的数据类型 bool

41 /// </summary>

42 Bit,

43

44 /// <summary>

45 /// 对应.NET中的数据类型 System.Decimal

46 /// </summary>

47 Decimal,

48

49 /// <summary>

50 /// 对应.NET中的数据类型 System.Decimal

51 /// </summary>

52 Numeric,

53

54 /// <summary>

55 /// 对应.NET中的数据类型 System.Decimal

56 /// </summary>

57 Money,

58

59 /// <summary>

60 /// 对应.NET中的数据类型

61 /// </summary>

62 Smallmoney,

63

64 /// <summary>

65 /// 对应.NET中的数据类型 System.Double

66 /// </summary>

67 Float,

68

69 /// <summary>

70 /// 对应.NET中的数据类型 System.Single

71 /// </summary>

72 Real,

73

74 /// <summary>

75 /// 对应.NET中的数据类型 System.DateTime

76 /// </summary>

77 Datetime,

78

79 /// <summary>

80 /// 对应.NET中的数据类型 System.DateTime

81 /// </summary>

82 Smalldatetime,

83

84 /// <summary>

85 /// 对应.NET中的数据类型 String

86 /// </summary>

87 Char,

88

89 /// <summary>

90 /// 对应.NET中的数据类型 String

91 /// </summary>

92 Varchar,

93

94 /// <summary>

95 /// 对应.NET中的数据类型 String

96 /// </summary>

97 Text,

98

99 /// <summary>

100 /// 对应.NET中的数据类型 String

101 /// </summary>

102 Nchar,

103

104 /// <summary>

105 /// 对应.NET中的数据类型 String

106 /// </summary>

107 Nvarchar,

108

109 /// <summary>

110 /// 对应.NET中的数据类型 String

111 /// </summary>

112 Ntext,

113

114 /// <summary>

115 /// 对应.NET中的数据类型 System.Byte[]

116 /// </summary>

117 Binary,

118

119 /// <summary>

120 /// 对应.NET中的数据类型 System.Byte[]

121 /// </summary>

122 Varbinary,

123

124 /// <summary>

125 /// 对应.NET中的数据类型 System.Byte[]

126 /// </summary>

127 Image,

128

129 /// <summary>

130 /// 对应.NET中的数据类型 System.DateTime

131 /// </summary>

132 Timestamp,

133

134 /// <summary>

135 /// 对应.NET中的数据类型 System.Guid

136 /// </summary>

137 Uniqueidentifier,

138

139 /// <summary>

140 /// 对应.NET中的数据类型 Object

141 /// </summary>

142 Variant

143

144 }

145 }

146

以上数据类型都是在程序设计中比较常用的,而且在我们在程序设计的时候,往往都会遇到类型不是完全匹配的时候,在后面的章节中将特殊的讲解一个数据类型与数据类型的不同。在使用CreateParameter() 创建占位符参数的时候,我们也要转化一下类型。之前我们使用SqlParameter 的时候,很多人就是new SqlParameter("@name","qingyuan") 这样对应。就默认为string 类型可以直接转化为sql中的nvarchar,varchar等类型,其实不然。中间还有一个转化过程。




.net
与SQL 类型的相互转化

1 /// <summary>

2 /// 数据库类型的转化

3 /// </summary>

4 /// <param name="type">程序中的类型</param>

5 /// <returns></returns>

6 private SqlDbType ConvertType(DataType type)

7 {

8 SqlDbType sqlType = SqlDbType.BigInt;

9 switch (type)

10 {

11 case DataType.Bigint:

12 sqlType = SqlDbType.BigInt;

13 break;

14 case DataType.Binary:

15 sqlType = SqlDbType.Binary;

16 break;

17 case DataType.Bit:

18 sqlType = SqlDbType.Bit;

19 break;

20 case DataType.Char:

21 sqlType = SqlDbType.Char;

22 break;

23 case DataType.Datetime:

24 sqlType = SqlDbType.DateTime;

25 break;

26 case DataType.Decimal:

27 sqlType = SqlDbType.Decimal;

28 break;

29 case DataType.Float:

30 sqlType = SqlDbType.Float;

31 break;

32 case DataType.Image:

33 sqlType = SqlDbType.Image;

34 break;

35 case DataType.Int:

36 sqlType = SqlDbType.Int;

37 break;

38 case DataType.Money:

39 sqlType = SqlDbType.Money;

40 break;

41 case DataType.Nchar:

42 sqlType = SqlDbType.NChar;

43 break;

44 case DataType.Ntext:

45 sqlType = SqlDbType.NText;

46 break;

47 case DataType.Numeric:

48 sqlType = SqlDbType.Decimal;

49 break;

50 case DataType.Nvarchar:

51 sqlType = SqlDbType.NVarChar;

52 break;

53 case DataType.Real:

54 sqlType = SqlDbType.Float;

55 break;

56 case DataType.Smalldatetime:

57 sqlType = SqlDbType.SmallDateTime;

58 break;

59 case DataType.Smallint:

60 sqlType = SqlDbType.SmallInt;

61 break;

62 case DataType.Smallmoney:

63 sqlType = SqlDbType.SmallMoney;

64 break;

65 case DataType.Text:

66 sqlType = SqlDbType.Text;

67 break;

68 case DataType.Timestamp:

69 sqlType = SqlDbType.Timestamp;

70 break;

71 case DataType.Tinyint:

72 sqlType = SqlDbType.TinyInt;

73 break;

74 case DataType.Uniqueidentifier:

75 sqlType = SqlDbType.UniqueIdentifier;

76 break;

77 case DataType.Varbinary:

78 sqlType = SqlDbType.VarBinary;

79 break;

80 case DataType.Varchar:

81 sqlType = SqlDbType.VarChar;

82 break;

83 case DataType.Variant:

84 sqlType = SqlDbType.Variant;

85 break;

86

87 }

88 return sqlType;

89 }

90

所以说做程序不能只看到表面现象,只有深入的去了解他们的原理,知识的使用才能游刃有余。即使千变万化,也是万变不离其宗。

说到这篇文章,我只能说我只写到了很肤浅的一部分。明天要去参加老赵的一个演讲,我想大家都应该这道他的主题是什么了,在文章的结尾我想说,.net 的确有他的奥妙之处。或许我们是觉得.net入门非常简单,这些我承认。说.net 是傻瓜式编程,其实是不是傻瓜式编程这个不是由语言决定的,关键在于你怎么去使用这个东西。C# 的确是一门非常优美的语言,我只能以这种言辞来表达。各种语言编程都有他的好处和坏处,不能从单一角度出发,只有你深入的了解了你就会发现它的美。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: