Mercurial > pub > bltoolkit
comparison Source/DataAccess/DataAccessor.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f990fcb411a9 |
---|---|
1 using System; | |
2 using System.Collections; | |
3 using System.Collections.Generic; | |
4 using System.Data; | |
5 using System.Data.SqlTypes; | |
6 using System.Diagnostics; | |
7 using System.IO; | |
8 using System.Reflection; | |
9 using System.Xml; | |
10 #if !SILVERLIGHT | |
11 using System.Xml.Linq; | |
12 #endif | |
13 | |
14 namespace BLToolkit.DataAccess | |
15 { | |
16 using Aspects; | |
17 using Common; | |
18 using Data; | |
19 using Data.DataProvider; | |
20 using Mapping; | |
21 using Patterns; | |
22 using Properties; | |
23 using Reflection; | |
24 using TypeBuilder; | |
25 | |
26 [DataAccessor, DebuggerStepThrough] | |
27 public abstract class DataAccessor : DataAccessorBase | |
28 { | |
29 #region Constructors | |
30 | |
31 protected DataAccessor() | |
32 { | |
33 } | |
34 | |
35 protected DataAccessor(DbManager dbManager) | |
36 : base(dbManager) | |
37 { | |
38 } | |
39 | |
40 protected DataAccessor(DbManager dbManager, bool dispose) | |
41 : base(dbManager, dispose) | |
42 { | |
43 } | |
44 | |
45 #endregion | |
46 | |
47 #region CreateInstance | |
48 | |
49 public static DataAccessor CreateInstance(Type type) | |
50 { | |
51 return (DataAccessor)Activator.CreateInstance(TypeFactory.GetType(type)); | |
52 } | |
53 | |
54 public static DataAccessor CreateInstance(Type type, InitContext context) | |
55 { | |
56 return (DataAccessor)Activator.CreateInstance(TypeFactory.GetType(type), context); | |
57 } | |
58 | |
59 public static DataAccessor CreateInstance(Type type, DbManager dbManager) | |
60 { | |
61 return CreateInstance(type, dbManager, false); | |
62 } | |
63 | |
64 public static DataAccessor CreateInstance( | |
65 Type type, | |
66 InitContext context, | |
67 DbManager dbManager) | |
68 { | |
69 return CreateInstance(type, context, dbManager, false); | |
70 } | |
71 | |
72 public static DataAccessor CreateInstance(Type type, DbManager dbManager, bool dispose) | |
73 { | |
74 var da = CreateInstance(type); | |
75 | |
76 da.SetDbManager(dbManager, dispose); | |
77 | |
78 return da; | |
79 } | |
80 | |
81 public static DataAccessor CreateInstance( | |
82 Type type, | |
83 InitContext context, | |
84 DbManager dbManager, | |
85 bool dispose) | |
86 { | |
87 var da = CreateInstance(type, context); | |
88 | |
89 da.SetDbManager(dbManager, dispose); | |
90 | |
91 return da; | |
92 } | |
93 | |
94 public static T CreateInstance<T>() where T : DataAccessor | |
95 { | |
96 return TypeFactory.CreateInstance<T>(); | |
97 } | |
98 | |
99 public static T CreateInstance<T>(DbManager dbManager) | |
100 where T : DataAccessor | |
101 { | |
102 return CreateInstance<T>(dbManager, false); | |
103 } | |
104 | |
105 public static T CreateInstance<T>(DbManager dbManager, bool dispose) | |
106 where T : DataAccessor | |
107 { | |
108 var da = TypeFactory.CreateInstance<T>(); | |
109 | |
110 da.SetDbManager(dbManager, dispose); | |
111 | |
112 return da; | |
113 } | |
114 | |
115 #endregion | |
116 | |
117 #region Protected Members | |
118 | |
119 #region Parameters | |
120 | |
121 [NoInterception] | |
122 protected virtual string GetQueryParameterName(DbManager db, string paramName) | |
123 { | |
124 return (string)db.DataProvider.Convert(paramName, ConvertType.NameToQueryParameter); | |
125 } | |
126 | |
127 [NoInterception] | |
128 protected virtual string GetSpParameterName(DbManager db, string paramName) | |
129 { | |
130 return (string)db.DataProvider.Convert(paramName, db.GetConvertTypeToParameter()); | |
131 } | |
132 | |
133 [NoInterception] | |
134 protected virtual IDbDataParameter[] PrepareParameters(DbManager db, object[] parameters) | |
135 { | |
136 return db.PrepareParameters(parameters); | |
137 } | |
138 | |
139 [NoInterception] | |
140 protected virtual IDbDataParameter GetParameter(DbManager db, string paramName) | |
141 { | |
142 var p = db.Parameter(paramName); | |
143 | |
144 if (p == null) | |
145 { | |
146 // This usually means that the parameter name is incorrect. | |
147 // | |
148 throw new DataAccessException(string.Format( | |
149 Resources.DataAccessot_ParameterNotFound, paramName)); | |
150 } | |
151 | |
152 // Input parameter mapping make no sence. | |
153 // | |
154 Debug.WriteLineIf(p.Direction == ParameterDirection.Input, | |
155 string.Format("'{0}.{1}' is an input parameter.", | |
156 db.Command.CommandText, paramName)); | |
157 | |
158 return p; | |
159 } | |
160 | |
161 [NoInterception] | |
162 protected virtual IDbDataParameter[] CreateParameters( | |
163 DbManager db, | |
164 object obj, | |
165 string[] outputParameters, | |
166 string[] inputOutputParameters, | |
167 string[] ignoreParameters, | |
168 params IDbDataParameter[] commandParameters) | |
169 { | |
170 return db.CreateParameters(obj, outputParameters, | |
171 inputOutputParameters, ignoreParameters, commandParameters); | |
172 } | |
173 | |
174 [NoInterception] | |
175 protected virtual IDbDataParameter[] CreateParameters( | |
176 DbManager db, | |
177 DataRow dataRow, | |
178 string[] outputParameters, | |
179 string[] inputOutputParameters, | |
180 string[] ignoreParameters, | |
181 params IDbDataParameter[] commandParameters) | |
182 { | |
183 return db.CreateParameters(dataRow, outputParameters, | |
184 inputOutputParameters, ignoreParameters, commandParameters); | |
185 } | |
186 | |
187 [NoInterception] | |
188 protected virtual string PrepareSqlQuery(DbManager db, int queryID, int uniqueID, string sqlQuery) | |
189 { | |
190 return sqlQuery; | |
191 } | |
192 | |
193 #endregion | |
194 | |
195 #region ExecuteDictionary | |
196 | |
197 protected void ExecuteDictionary( | |
198 DbManager db, | |
199 IDictionary dictionary, | |
200 Type objectType, | |
201 Type keyType, | |
202 string methodName) | |
203 { | |
204 var isIndex = TypeHelper.IsSameOrParent(typeof(CompoundValue), keyType); | |
205 var mms = new SqlQuery(Extensions).GetKeyFieldList(db, objectType); | |
206 | |
207 if (mms.Length == 0) | |
208 throw new DataAccessException(string.Format( | |
209 Resources.DataAccessor_UnknownIndex, | |
210 GetType().Name, methodName)); | |
211 | |
212 if (mms.Length > 1 && keyType != typeof(object) && !isIndex) | |
213 throw new DataAccessException(string.Format( | |
214 Resources.DataAccessor_InvalidKeyType, | |
215 GetType().Name, methodName)); | |
216 | |
217 if (isIndex || mms.Length > 1) | |
218 { | |
219 var fields = new string[mms.Length]; | |
220 | |
221 for (var i = 0; i < mms.Length; i++) | |
222 fields[i] = mms[i].MemberName; | |
223 | |
224 db.ExecuteDictionary(dictionary, new MapIndex(fields), objectType, null); | |
225 } | |
226 else | |
227 { | |
228 db.ExecuteDictionary(dictionary, mms[0].MemberName, objectType, null); | |
229 } | |
230 } | |
231 | |
232 protected void ExecuteDictionary<TValue>( | |
233 DbManager db, | |
234 IDictionary<CompoundValue, TValue> dictionary, | |
235 Type objectType, | |
236 string methodName) | |
237 { | |
238 var mms = new SqlQuery(Extensions).GetKeyFieldList(db, objectType); | |
239 | |
240 if (mms.Length == 0) | |
241 throw new DataAccessException(string.Format( | |
242 Resources.DataAccessor_UnknownIndex, | |
243 GetType().Name, methodName)); | |
244 | |
245 var fields = new string[mms.Length]; | |
246 | |
247 for (var i = 0; i < mms.Length; i++) | |
248 fields[i] = mms[i].MemberName; | |
249 | |
250 db.ExecuteDictionary(dictionary, new MapIndex(fields), objectType, null); | |
251 } | |
252 | |
253 protected void ExecuteDictionary<TKey, TValue>( | |
254 DbManager db, | |
255 IDictionary<TKey, TValue> dictionary, | |
256 Type objectType, | |
257 string methodName) | |
258 { | |
259 var mms = new SqlQuery(Extensions).GetKeyFieldList(db, objectType); | |
260 | |
261 if (mms.Length == 0) | |
262 throw new DataAccessException(string.Format( | |
263 Resources.DataAccessor_UnknownIndex, | |
264 GetType().Name, methodName)); | |
265 | |
266 if (mms.Length != 1) | |
267 throw new DataAccessException(string.Format( | |
268 Resources.DataAccessor_IndexIsComplex, | |
269 GetType().Name, methodName)); | |
270 | |
271 db.ExecuteDictionary(dictionary, mms[0].MemberName, objectType, null); | |
272 } | |
273 | |
274 protected void ExecuteScalarDictionary( | |
275 DbManager db, | |
276 IDictionary dictionary, | |
277 Type objectType, | |
278 Type keyType, | |
279 string methodName, | |
280 NameOrIndexParameter scalarField, | |
281 Type elementType) | |
282 { | |
283 var isIndex = TypeHelper.IsSameOrParent(typeof(CompoundValue), keyType); | |
284 var mms = new SqlQuery(Extensions).GetKeyFieldList(db, objectType); | |
285 | |
286 if (mms.Length == 0) | |
287 throw new DataAccessException(string.Format( | |
288 Resources.DataAccessor_UnknownIndex, | |
289 GetType().Name, methodName)); | |
290 | |
291 if (mms.Length > 1 && keyType != typeof(object) && !isIndex) | |
292 throw new DataAccessException(string.Format( | |
293 Resources.DataAccessor_InvalidKeyType, | |
294 GetType().Name, methodName)); | |
295 | |
296 if (isIndex || mms.Length > 1) | |
297 { | |
298 var fields = new string[mms.Length]; | |
299 | |
300 for (var i = 0; i < mms.Length; i++) | |
301 fields[i] = mms[i].Name; | |
302 | |
303 db.ExecuteScalarDictionary(dictionary, new MapIndex(fields), scalarField, elementType); | |
304 } | |
305 else | |
306 { | |
307 db.ExecuteScalarDictionary( | |
308 dictionary, | |
309 mms[0].Name, | |
310 keyType, | |
311 scalarField, | |
312 elementType); | |
313 } | |
314 } | |
315 | |
316 #endregion | |
317 | |
318 #region ExecuteEnumerable | |
319 | |
320 protected IEnumerable<T> ExecuteEnumerable<T>(DbManager db, Type objectType, bool disposeDbManager) | |
321 { | |
322 try | |
323 { | |
324 using (var rd = db.ExecuteReader()) | |
325 { | |
326 if (rd.Read()) | |
327 { | |
328 var dest = MappingSchema.GetObjectMapper(objectType); | |
329 var source = MappingSchema.CreateDataReaderMapper(rd); | |
330 | |
331 var ctx = new InitContext | |
332 { | |
333 MappingSchema = MappingSchema, | |
334 ObjectMapper = dest, | |
335 DataSource = source, | |
336 SourceObject = rd | |
337 }; | |
338 | |
339 var index = MappingSchema.GetIndex(source, dest); | |
340 var mappers = ctx.MappingSchema.GetValueMappers(source, dest, index); | |
341 | |
342 do | |
343 { | |
344 var destObject = (T)dest.CreateInstance(ctx); | |
345 | |
346 if (ctx.StopMapping) | |
347 yield return destObject; | |
348 | |
349 var smDest = destObject as ISupportMapping; | |
350 | |
351 if (smDest != null) | |
352 { | |
353 smDest.BeginMapping(ctx); | |
354 | |
355 if (ctx.StopMapping) | |
356 yield return destObject; | |
357 } | |
358 | |
359 MappingSchema.MapInternal(source, rd, dest, destObject, index, mappers); | |
360 | |
361 if (smDest != null) | |
362 smDest.EndMapping(ctx); | |
363 | |
364 yield return destObject; | |
365 } while (rd.Read()); | |
366 } | |
367 } | |
368 } | |
369 finally | |
370 { | |
371 if (disposeDbManager) | |
372 db.Dispose(); | |
373 } | |
374 } | |
375 | |
376 protected IEnumerable ExecuteEnumerable(DbManager db, Type objectType, bool disposeDbManager) | |
377 { | |
378 var ms = db.MappingSchema; | |
379 | |
380 if (disposeDbManager) | |
381 { | |
382 using (db) | |
383 using (var rd = db.ExecuteReader()) | |
384 while (rd.Read()) | |
385 yield return ms.MapDataReaderToObject(rd, objectType); | |
386 } | |
387 else | |
388 { | |
389 using (var rd = db.ExecuteReader()) | |
390 while (rd.Read()) | |
391 yield return ms.MapDataReaderToObject(rd, objectType); | |
392 } | |
393 } | |
394 | |
395 #endregion | |
396 | |
397 #region Convert | |
398 | |
399 #region Primitive Types | |
400 | |
401 [CLSCompliant(false)] | |
402 [NoInterception] | |
403 protected virtual SByte ConvertToSByte(DbManager db, object value, object parameter) | |
404 { | |
405 return db.MappingSchema.ConvertToSByte(value); | |
406 } | |
407 | |
408 [NoInterception] | |
409 protected virtual Int16 ConvertToInt16(DbManager db, object value, object parameter) | |
410 { | |
411 return db.MappingSchema.ConvertToInt16(value); | |
412 } | |
413 | |
414 [NoInterception] | |
415 protected virtual Int32 ConvertToInt32(DbManager db, object value, object parameter) | |
416 { | |
417 return db.MappingSchema.ConvertToInt32(value); | |
418 } | |
419 | |
420 [NoInterception] | |
421 protected virtual Int64 ConvertToInt64(DbManager db, object value, object parameter) | |
422 { | |
423 return db.MappingSchema.ConvertToInt64(value); | |
424 } | |
425 | |
426 [NoInterception] | |
427 protected virtual Byte ConvertToByte(DbManager db, object value, object parameter) | |
428 { | |
429 return db.MappingSchema.ConvertToByte(value); | |
430 } | |
431 | |
432 [CLSCompliant(false)] | |
433 [NoInterception] | |
434 protected virtual UInt16 ConvertToUInt16(DbManager db, object value, object parameter) | |
435 { | |
436 return db.MappingSchema.ConvertToUInt16(value); | |
437 } | |
438 | |
439 [CLSCompliant(false)] | |
440 [NoInterception] | |
441 protected virtual UInt32 ConvertToUInt32(DbManager db, object value, object parameter) | |
442 { | |
443 return db.MappingSchema.ConvertToUInt32(value); | |
444 } | |
445 | |
446 [CLSCompliant(false)] | |
447 [NoInterception] | |
448 protected virtual UInt64 ConvertToUInt64(DbManager db, object value, object parameter) | |
449 { | |
450 return db.MappingSchema.ConvertToUInt64(value); | |
451 } | |
452 | |
453 [NoInterception] | |
454 protected virtual Char ConvertToChar(DbManager db, object value, object parameter) | |
455 { | |
456 return db.MappingSchema.ConvertToChar(value); | |
457 } | |
458 | |
459 [NoInterception] | |
460 protected virtual Single ConvertToSingle(DbManager db, object value, object parameter) | |
461 { | |
462 return db.MappingSchema.ConvertToSingle(value); | |
463 } | |
464 | |
465 [NoInterception] | |
466 protected virtual Double ConvertToDouble(DbManager db, object value, object parameter) | |
467 { | |
468 return db.MappingSchema.ConvertToDouble(value); | |
469 } | |
470 | |
471 [NoInterception] | |
472 protected virtual Boolean ConvertToBoolean(DbManager db, object value, object parameter) | |
473 { | |
474 return db.MappingSchema.ConvertToBoolean(value); | |
475 } | |
476 | |
477 #endregion | |
478 | |
479 #region Simple Types | |
480 | |
481 [NoInterception] | |
482 protected virtual String ConvertToString(DbManager db, object value, object parameter) | |
483 { | |
484 return db.MappingSchema.ConvertToString(value); | |
485 } | |
486 | |
487 [NoInterception] | |
488 protected virtual DateTime ConvertToDateTime(DbManager db, object value, object parameter) | |
489 { | |
490 return db.MappingSchema.ConvertToDateTime(value); | |
491 } | |
492 | |
493 [NoInterception] | |
494 protected virtual DateTimeOffset ConvertToDateTimeOffset(DbManager db, object value, object parameter) | |
495 { | |
496 return db.MappingSchema.ConvertToDateTimeOffset(value); | |
497 } | |
498 | |
499 [NoInterception] | |
500 protected virtual System.Data.Linq.Binary ConvertToLinqBinary(DbManager db, object value, object parameter) | |
501 { | |
502 return db.MappingSchema.ConvertToLinqBinary(value); | |
503 } | |
504 | |
505 [NoInterception] | |
506 protected virtual Decimal ConvertToDecimal(DbManager db, object value, object parameter) | |
507 { | |
508 return db.MappingSchema.ConvertToDecimal(value); | |
509 } | |
510 | |
511 [NoInterception] | |
512 protected virtual Guid ConvertToGuid(DbManager db, object value, object parameter) | |
513 { | |
514 return db.MappingSchema.ConvertToGuid(value); | |
515 } | |
516 | |
517 [NoInterception] | |
518 protected virtual Stream ConvertToStream(DbManager db, object value, object parameter) | |
519 { | |
520 return db.MappingSchema.ConvertToStream(value); | |
521 } | |
522 | |
523 [NoInterception] | |
524 protected virtual XmlReader ConvertToXmlReader(DbManager db, object value, object parameter) | |
525 { | |
526 return db.MappingSchema.ConvertToXmlReader(value); | |
527 } | |
528 | |
529 [NoInterception] | |
530 protected virtual XmlDocument ConvertToXmlDocument(DbManager db, object value, object parameter) | |
531 { | |
532 return db.MappingSchema.ConvertToXmlDocument(value); | |
533 } | |
534 | |
535 #if !SILVERLIGHT | |
536 [NoInterception] | |
537 protected virtual XElement ConvertToXElement(DbManager db, object value, object parameter) | |
538 { | |
539 return db.MappingSchema.ConvertToXElement(value); | |
540 } | |
541 #endif | |
542 | |
543 [NoInterception] | |
544 protected virtual Byte[] ConvertToByteArray(DbManager db, object value, object parameter) | |
545 { | |
546 return db.MappingSchema.ConvertToByteArray(value); | |
547 } | |
548 | |
549 [NoInterception] | |
550 protected virtual Char[] ConvertToCharArray(DbManager db, object value, object parameter) | |
551 { | |
552 return db.MappingSchema.ConvertToCharArray(value); | |
553 } | |
554 | |
555 #endregion | |
556 | |
557 #region SqlTypes | |
558 | |
559 [NoInterception] | |
560 protected virtual SqlByte ConvertToSqlByte(DbManager db, object value, object parameter) | |
561 { | |
562 return db.MappingSchema.ConvertToSqlByte(value); | |
563 } | |
564 | |
565 [NoInterception] | |
566 protected virtual SqlInt16 ConvertToSqlInt16(DbManager db, object value, object parameter) | |
567 { | |
568 return db.MappingSchema.ConvertToSqlInt16(value); | |
569 } | |
570 | |
571 [NoInterception] | |
572 protected virtual SqlInt32 ConvertToSqlInt32(DbManager db, object value, object parameter) | |
573 { | |
574 return db.MappingSchema.ConvertToSqlInt32(value); | |
575 } | |
576 | |
577 [NoInterception] | |
578 protected virtual SqlInt64 ConvertToSqlInt64(DbManager db, object value, object parameter) | |
579 { | |
580 return db.MappingSchema.ConvertToSqlInt64(value); | |
581 } | |
582 | |
583 [NoInterception] | |
584 protected virtual SqlSingle ConvertToSqlSingle(DbManager db, object value, object parameter) | |
585 { | |
586 return db.MappingSchema.ConvertToSqlSingle(value); | |
587 } | |
588 | |
589 [NoInterception] | |
590 protected virtual SqlBoolean ConvertToSqlBoolean(DbManager db, object value, object parameter) | |
591 { | |
592 return db.MappingSchema.ConvertToSqlBoolean(value); | |
593 } | |
594 | |
595 [NoInterception] | |
596 protected virtual SqlDouble ConvertToSqlDouble(DbManager db, object value, object parameter) | |
597 { | |
598 return db.MappingSchema.ConvertToSqlDouble(value); | |
599 } | |
600 | |
601 [NoInterception] | |
602 protected virtual SqlDateTime ConvertToSqlDateTime(DbManager db, object value, object parameter) | |
603 { | |
604 return db.MappingSchema.ConvertToSqlDateTime(value); | |
605 } | |
606 | |
607 [NoInterception] | |
608 protected virtual SqlDecimal ConvertToSqlDecimal(DbManager db, object value, object parameter) | |
609 { | |
610 return db.MappingSchema.ConvertToSqlDecimal(value); | |
611 } | |
612 | |
613 [NoInterception] | |
614 protected virtual SqlMoney ConvertToSqlMoney(DbManager db, object value, object parameter) | |
615 { | |
616 return db.MappingSchema.ConvertToSqlMoney(value); | |
617 } | |
618 | |
619 [NoInterception] | |
620 protected virtual SqlGuid ConvertToSqlGuid(DbManager db, object value, object parameter) | |
621 { | |
622 return db.MappingSchema.ConvertToSqlGuid(value); | |
623 } | |
624 | |
625 [NoInterception] | |
626 protected virtual SqlString ConvertToSqlString(DbManager db, object value, object parameter) | |
627 { | |
628 return db.MappingSchema.ConvertToSqlString(value); | |
629 } | |
630 | |
631 #endregion | |
632 | |
633 #region General case | |
634 | |
635 [NoInterception] | |
636 protected virtual object ConvertChangeType( | |
637 DbManager db, | |
638 object value, | |
639 Type conversionType, | |
640 object parameter) | |
641 { | |
642 return db.MappingSchema.ConvertChangeType(value, conversionType); | |
643 } | |
644 | |
645 #endregion | |
646 | |
647 #endregion | |
648 | |
649 #region IsNull | |
650 | |
651 /// <summary> | |
652 /// Reserved for internal BLToolkit use. | |
653 /// </summary> | |
654 public interface INullableInternal | |
655 { | |
656 bool IsNull { [MustImplement(false, false)] get; } | |
657 } | |
658 | |
659 [NoInterception] | |
660 protected virtual bool IsNull( | |
661 DbManager db, | |
662 object value, | |
663 object parameter) | |
664 { | |
665 // Speed up for scalar and nullable types. | |
666 // | |
667 switch (System.Convert.GetTypeCode(value)) | |
668 { | |
669 // null, DBNull.Value, Nullable<T> without a value. | |
670 // | |
671 case TypeCode.Empty: | |
672 case TypeCode.DBNull: | |
673 return true; | |
674 | |
675 case TypeCode.Object: | |
676 break; | |
677 | |
678 // int, byte, string, DateTime and other primitives except Guid. | |
679 // Also Nullable<T> with a value. | |
680 // | |
681 default: | |
682 return false; | |
683 } | |
684 | |
685 // Speed up for SqlTypes. | |
686 // | |
687 var nullable = value as INullable; | |
688 if (nullable != null) | |
689 return nullable.IsNull; | |
690 | |
691 // All other types which have 'IsNull' property but does not implement 'INullable' interface. | |
692 // For example: 'Oracle.DataAccess.Types.OracleDecimal'. | |
693 // | |
694 // For types without 'IsNull' property the return value is always false. | |
695 // | |
696 var nullableInternal = (INullableInternal)DuckTyping.Implement(typeof(INullableInternal), value); | |
697 | |
698 return nullableInternal.IsNull; | |
699 } | |
700 | |
701 #endregion | |
702 | |
703 protected virtual SqlQueryAttribute GetSqlQueryAttribute(MethodInfo methodInfo) | |
704 { | |
705 var attrs = methodInfo.GetCustomAttributes(typeof(SqlQueryAttribute), true); | |
706 return (SqlQueryAttribute)attrs[0]; | |
707 } | |
708 | |
709 #endregion | |
710 } | |
711 } |