| 0 | 1 <% title # Introduction to abstract data accessors %> | 
|  | 2 <% order # 1 %> | 
|  | 3 <h4>Introduction</h4> | 
|  | 4 | 
|  | 5 <p class='j'> | 
|  | 6 Before we start talking about the data accessors, let us create a few examples of | 
|  | 7 typical data accessor methods. | 
|  | 8 </p> | 
|  | 9 <p class='j'> | 
|  | 10 The following table contains three stored procedures and | 
|  | 11 three data access methods implementing the stored procedure calls. | 
|  | 12 </p> | 
|  | 13 | 
|  | 14 <table width='100%'> | 
|  | 15 <tr><th>Stored procedure</th><th>Data access method</th></tr> | 
|  | 16 <tr><td colspan=2 style='padding-top:7px'> | 
|  | 17 The first stored procedure takes filter and page parameters and returns recordset from the Person table. | 
|  | 18 </td></tr> | 
|  | 19 <tr> | 
|  | 20 <td width=50% height=100%><% sql # | 
|  | 21 CREATE Procedure GetPersonListByName( | 
|  | 22 	@firstName  varchar(50), | 
|  | 23 	@lastName   varchar(50), | 
|  | 24 	@pageNumber int, | 
|  | 25 	@pageSize   int) | 
|  | 26 AS | 
|  | 27 	-- stored procedure implementation | 
|  | 28 	-- | 
|  | 29 %></td> | 
|  | 30 <td width=50%><% cs # | 
|  | 31 public List<Person> GetPersonListByName( | 
|  | 32 	string firstName, | 
|  | 33 	string lastName, | 
|  | 34 	int    pageNumber, | 
|  | 35 	int    pageSize) | 
|  | 36 { | 
|  | 37 	// method implementation. | 
|  | 38 } | 
|  | 39 %></td> | 
|  | 40 </tr> | 
|  | 41 <tr><td colspan=2> | 
|  | 42 Second example will return single <b>Person</b> record by <b>id</b>. | 
|  | 43 </td></tr> | 
|  | 44 <tr> | 
|  | 45 <td width=50% height=100%><% sql # | 
|  | 46 CREATE Procedure GetPersonByID(@id int) | 
|  | 47 AS | 
|  | 48 	-- stored procedure implementation | 
|  | 49 	-- | 
|  | 50 %> | 
|  | 51 </td> | 
|  | 52 <td width=50%><% cs # | 
|  | 53 public Person GetPersonByID(int id) | 
|  | 54 { | 
|  | 55     // method implementation. | 
|  | 56 } | 
|  | 57 %></td> | 
|  | 58 </tr> | 
|  | 59 <tr><td colspan=2> | 
|  | 60 The last example will delete a record from the database by <b>id</b>. | 
|  | 61 </td></tr> | 
|  | 62 <tr> | 
|  | 63 <td width=50% height=100%><% sql # | 
|  | 64 CREATE Procedure DeletePersonByID(@id int) | 
|  | 65 AS | 
|  | 66 	-- stored procedure implementation | 
|  | 67 	-- | 
|  | 68 %></td> | 
|  | 69 <td width=50%><% cs # | 
|  | 70 public void DeletePersonByID(int id) | 
|  | 71 { | 
|  | 72     // method implementation. | 
|  | 73 } | 
|  | 74 %></td> | 
|  | 75 </tr> | 
|  | 76 </table> | 
|  | 77 | 
|  | 78 <p class='j'>Now lets see what we can say if we compare the stored procedure and C# method signatures. | 
|  | 79 <ol> | 
|  | 80 <li>Stored procedure and method names match up.</li> | 
|  | 81 <li>Sequential order, method parameter types and names correspond to stored procedure parameters.</li> | 
|  | 82 <li>Methods' return values can give us an idea what <b>Execute</b> method we | 
|  | 83 should utilize and what object type has to be used to map data from recordset if needed.</li> | 
|  | 84 </ol> | 
|  | 85 </p> | 
|  | 86 | 
|  | 87 <p class='j'> | 
|  | 88 As demonstrated above method definition contains all the information we need | 
|  | 89 to implement the method body. Actually, by defining the method signatures, we | 
|  | 90 completed the most intelligent part of data accessor development. The rest of | 
|  | 91 work is definitely a monkey's job. Honestly, I got bored of being just a coding | 
|  | 92 machine writing the same data access code over and over again, especially | 
|  | 93 understanding that this process can be automated. | 
|  | 94 </p> | 
|  | 95 <p class='j'> | 
|  | 96 This introduction shows how to avoid the implementation step of data access | 
|  | 97 development and how to reduce this routine process to the method declaration. | 
|  | 98 </p> | 
|  | 99 | 
|  | 100 <h4>Abstract classes</h4> | 
|  | 101 | 
|  | 102 <p class='j'> | 
|  | 103 Unfortunately, mainstream .NET languages still do not have a compile-time | 
|  | 104 transformation system like some functional or <a href="http://nemerle.org/Macros">hybrid</a> languages do. | 
|  | 105 All we have today is pre-compile- and run-time code generation. | 
|  | 106 </p> | 
|  | 107 <p class='j'> | 
|  | 108 This introduction concentrates on run-time code generation and its support by | 
|  | 109 <a href="http://www.bltoolkit.net/">Business Logic Toolkit for .NET</a>. | 
|  | 110 </p> | 
|  | 111 <p class='j'> | 
|  | 112 Let us step back and bring the methods from the previous examples together in one class. | 
|  | 113 Ideally, this data accessor class could look like the following: | 
|  | 114 </p> | 
|  | 115 <% cs # | 
|  | 116 using System; | 
|  | 117 using System.Collections.Generic; | 
|  | 118 | 
|  | 119 public class PersonAccessor | 
|  | 120 { | 
|  | 121 	public List<Person> GetPersonListByName( | 
|  | 122 		string firstName, string lastName, int pageNumber, int pageSize); | 
|  | 123 | 
|  | 124 	public Person GetPersonByID   (int id); | 
|  | 125 	public void   DeletePersonByID(int id); | 
|  | 126 } | 
|  | 127 %> | 
|  | 128 | 
|  | 129 <p class='j'> | 
|  | 130 The bad news about this sample is that we cannot use such syntax as the | 
|  | 131 compiler expects the method's body implementation. | 
|  | 132 </p> | 
|  | 133 <p class='j'> | 
|  | 134 The good news is we can use abstract classes and methods that give us quite | 
|  | 135 similar, compilable source code. | 
|  | 136 </p> | 
|  | 137 <% cs # | 
|  | 138 using System; | 
|  | 139 using System.Collections.Generic; | 
|  | 140 | 
|  | 141 public /*[a]*/abstract/*[/a]*/ class PersonAccessor | 
|  | 142 { | 
|  | 143 	public /*[a]*/abstract/*[/a]*/ List<Person> GetPersonListByName( | 
|  | 144 		string firstName, string lastName, int pageNumber, int pageSize); | 
|  | 145 | 
|  | 146 	public /*[a]*/abstract/*[/a]*/ Person GetPersonByID   (int id); | 
|  | 147 	public /*[a]*/abstract/*[/a]*/ void   DeletePersonByID(int id); | 
|  | 148 } | 
|  | 149 %> | 
|  | 150 | 
|  | 151 <p class='j'>This code is 100% valid and our next step is to make it workable.</p> | 
|  | 152 | 
|  | 153 <H4>Abstract DataAccessor</H4> | 
|  | 154 | 
|  | 155 <p class='j'> | 
|  | 156 Business Logic Toolkit provides the <b>DataAccessor</b> class, which is | 
|  | 157 used as a base class to develop data accessor classes. If we add | 
|  | 158 <b>DataAccessor</b> to our previous example, it will look like the following: | 
|  | 159 </p> | 
|  | 160 <% cs # | 
|  | 161 using System; | 
|  | 162 using System.Collections.Generic; | 
|  | 163 | 
|  | 164 public abstract class PersonAccessor : /*[a]*/DataAccessor/*[/a]*/ | 
|  | 165 { | 
|  | 166 	public abstract List<Person> GetPersonListByName( | 
|  | 167 		string firstName, string lastName, int pageNumber, int pageSize); | 
|  | 168 | 
|  | 169 	public abstract Person GetPersonByID   (int id); | 
|  | 170 	public abstract void   DeletePersonByID(int id); | 
|  | 171 } | 
|  | 172 %> | 
|  | 173 | 
|  | 174 <p class='j'>That's it! Now this class is complete and fully functional. The code below shows how to use it:</p> | 
|  | 175 | 
|  | 176 <% cs # | 
|  | 177 using System; | 
|  | 178 using System.Collections.Generic; | 
|  | 179 | 
|  | 180 using BLToolkit.Reflection; | 
|  | 181 | 
|  | 182 namespace DataAccess | 
|  | 183 { | 
|  | 184 	class Program | 
|  | 185 	{ | 
|  | 186 		static void Main(string[] args) | 
|  | 187 		{ | 
|  | 188 			PersonAccessor pa = /*[a]*/TypeAccessor/*[/a]*/<PersonAccessor>./*[a]*/CreateInstance/*[/a]*/(); | 
|  | 189 | 
|  | 190 			List<Person> list = pa.GetPersonListByName("Crazy", "Frog", 0, 20); | 
|  | 191 | 
|  | 192 			foreach (Person p in list) | 
|  | 193 				Console.Write("{0} {1}", p.FirstName, p.LastName); | 
|  | 194 		} | 
|  | 195 	} | 
|  | 196 } | 
|  | 197 %> | 
|  | 198 | 
|  | 199 <p class='j'> | 
|  | 200 The only magic here is the <b>TypeAccessor.CreateInstance</b> method. First of all this | 
|  | 201 method creates a new class inherited from the <b>PersonAccessor</b> class and | 
|  | 202 then generates abstract method bodies depending on each method declaration. | 
|  | 203 If we wrote those methods manually, we could get something like the following: | 
|  | 204 </p> | 
|  | 205 <% cs # | 
|  | 206 using System; | 
|  | 207 using System.Collections.Generic; | 
|  | 208 | 
|  | 209 using BLToolkit.Data; | 
|  | 210 | 
|  | 211 namespace Example.BLToolkitExtension | 
|  | 212 { | 
|  | 213 	public sealed class PersonAccessor : Example.PersonAccessor | 
|  | 214 	{ | 
|  | 215 		public override List<Person> GetPersonListByName( | 
|  | 216 			string firstName, | 
|  | 217 			string lastName, | 
|  | 218 			int    pageNumber, | 
|  | 219 			int    pageSize) | 
|  | 220 		{ | 
|  | 221 			using (DbManager db = GetDbManager()) | 
|  | 222 			{ | 
|  | 223 				return db | 
|  | 224 					.SetSpCommand("GetPersonListByName", | 
|  | 225 						db.Parameter("@firstName",  firstName), | 
|  | 226 						db.Parameter("@lastName",   lastName), | 
|  | 227 						db.Parameter("@pageNumber", pageNumber), | 
|  | 228 						db.Parameter("@pageSize",   pageSize)) | 
|  | 229 					.ExecuteList<Person>(); | 
|  | 230 			} | 
|  | 231 		} | 
|  | 232 | 
|  | 233 		public override Person GetPersonByID(int id) | 
|  | 234 		{ | 
|  | 235 			using (DbManager db = GetDbManager()) | 
|  | 236 			{ | 
|  | 237 				return db | 
|  | 238 					.SetSpCommand("GetPersonByID", db.Parameter("@id", id)) | 
|  | 239 					.ExecuteObject<Person>(); | 
|  | 240 			} | 
|  | 241 		} | 
|  | 242 | 
|  | 243 		public override void DeletePersonByID(int id) | 
|  | 244 		{ | 
|  | 245 			using (DbManager db = GetDbManager()) | 
|  | 246 			{ | 
|  | 247 				db | 
|  | 248 					.SetSpCommand("DeletePersonByID", db.Parameter("@id", id)) | 
|  | 249 					.ExecuteNonQuery(); | 
|  | 250 			} | 
|  | 251 		} | 
|  | 252 	} | 
|  | 253 } | 
|  | 254 %> | 
|  | 255 | 
|  | 256 <p class='j'> | 
|  | 257 (The <a href='..\Data\index.htm'>DbManager</a> class is another BLToolkit class used for 'low-level' database access). | 
|  | 258 </p> | 
|  | 259 | 
|  | 260 <p class="j"> | 
|  | 261 Every part of the method declaration is important. | 
|  | 262 Method's return value specifies one of the Execute methods in the following way: | 
|  | 263 <table class='data'> | 
|  | 264 <tr><th>Return Type</th><th>Execute Method</th></tr> | 
|  | 265 <tr><td><i>IDataReader</i> interface</td><td>ExecuteReader</td></tr> | 
|  | 266 <tr><td>Subclass of <i>DataSet</i></td><td>ExecuteDataSet</td></tr> | 
|  | 267 <tr><td>Subclass of <i>DataTable</i></td><td>ExecuteDataTable</td></tr> | 
|  | 268 <tr><td>Class implementing the <i>IList</i> interface</td><td><a href="ExecuteList.htm">ExecuteList</a> or <a href="ExecuteList.htm">ExecuteScalarList</a></td></tr> | 
|  | 269 <tr><td>Class implementing the <i>IDictionary</i> interface</td><td><a href="ExecuteDictionary.htm">ExecuteDictionary</a> or <a href="ExecuteDictionary.htm">ExecuteScalarDictionary</a></td></tr> | 
|  | 270 <tr><td><i>void</i></td><td>ExecuteNonQuery</td></tr> | 
|  | 271 <tr><td><i>string</i>, <i>byte[]</i> or value type</td><td><a href="ExecuteScalar.htm">ExecuteScalar</a></td></tr> | 
|  | 272 <tr><td>In any other case</td><td><a href="ExecuteObject.htm">ExecuteObject</a></td></tr> | 
|  | 273 </table> | 
|  | 274 The method name explicitly defines the action name, which is converted to the stored procedure name. | 
|  | 275 Type, sequential order, and name of the method parameters are mapped to the command parameters. | 
|  | 276 Exceptions from this rule are: | 
|  | 277 <br> | 
|  | 278 <div style='margin:-10px 0px -0px -10px'><ul compact="compact"> | 
|  | 279 <li>a parameter of <a href="../Data/index.htm"><i>DbManager</i></a> type. In this case generator uses provided <a href="../Data/index.htm"><i>DbManager</i></a> to call the command.</li> | 
|  | 280 <li>parameters decorated with attribute <a href='#FormatAttribute'>FormatAttribute</a>, <a href='#DestinationAttribute'>DestinationAttribute</a>.</li> | 
|  | 281 </ul></div> | 
|  | 282 </p> | 
|  | 283 | 
|  | 284 <h4>Generating process control</h4> | 
|  | 285 | 
|  | 286 <p class='j'> | 
|  | 287 The <b>PersonAccessor</b> class above is a very simple example and, of | 
|  | 288 course, it seems too ideal to be real. In real life, we need more flexibility | 
|  | 289 and more control over the generated code. BLToolkit contains a bunch of | 
|  | 290 attributes to control DataAccessor generation in addition to <b>DataAccessor</b> virtual members. | 
|  | 291 </p> | 
|  | 292 | 
|  | 293 <h5>Method CreateDbManager</h5> | 
|  | 294 | 
|  | 295 <% cs # | 
|  | 296 protected virtual DbManager CreateDbManager() | 
|  | 297 { | 
|  | 298     return new DbManager(); | 
|  | 299 } | 
|  | 300 %> | 
|  | 301 | 
|  | 302 <p class='j'> | 
|  | 303 By default, this method creates a new instance of <b>DbManager</b> that uses default database configuration. | 
|  | 304 You can change this behavior by overriding this method. For example: | 
|  | 305 </p> | 
|  | 306 <% cs # | 
|  | 307 public abstract class OracleDataAccessor : DataAccessor | 
|  | 308 { | 
|  | 309 	protected override DbManager CreateDbManager() | 
|  | 310 	{ | 
|  | 311 		return new DbManager("Oracle", "Production"); | 
|  | 312 	} | 
|  | 313 } | 
|  | 314 %> | 
|  | 315 | 
|  | 316 <p class='j'> | 
|  | 317 This code will use the <i>Oracle</i> data provider and <i>Production</i> configuration. | 
|  | 318 </p> | 
|  | 319 | 
|  | 320 <a name='GetDefaultSpName'></a><h5>Method GetDefaultSpName</h5> | 
|  | 321 | 
|  | 322 <% cs # | 
|  | 323 protected virtual string GetDefaultSpName(string typeName, string actionName) | 
|  | 324 { | 
|  | 325 	return typeName == null? | 
|  | 326 		actionName: | 
|  | 327 		string.Format("{0}_{1}", typeName, actionName); | 
|  | 328 } | 
|  | 329 %> | 
|  | 330 | 
|  | 331 <p class='j'> | 
|  | 332 As I mentioned, the method name explicitly defines the so-called action name. | 
|  | 333 The final stored procedure name is created by the <b>GetDefaultSpName</b> | 
|  | 334 method. The default implementation uses the following naming convention: | 
|  | 335 </p> | 
|  | 336 | 
|  | 337 <ul> | 
|  | 338 <li> | 
|  | 339 If type name is provided, the method constructs the stored proc name by | 
|  | 340 concatenating the type and action names. Thus, if the type name is "Person" and | 
|  | 341 the action name is "GetAll", the resulting sproc name will be "Person_GetAll". | 
|  | 342 </li> | 
|  | 343 <li> | 
|  | 344 If the type name is NOT provided, the stored procedure name will equal the | 
|  | 345 action name.</li> | 
|  | 346 </ul> | 
|  | 347 | 
|  | 348 <p class='j'> | 
|  | 349 You can easily change this behavior. For example, for the naming convention "p_Person_GetAll", | 
|  | 350 the method implementation can be the following: | 
|  | 351 </p> | 
|  | 352 <% cs # | 
|  | 353 public abstract class MyBaseDataAccessor<T,A> : DataAccessor<T,A> | 
|  | 354     where A : DataAccessor<T,A> | 
|  | 355 { | 
|  | 356     protected override string GetDefaultSpName(string typeName, string actionName) | 
|  | 357     { | 
|  | 358         return string.Format("p_{0}_{1}", typeName, actionName); | 
|  | 359     } | 
|  | 360 } | 
|  | 361 %> | 
|  | 362 | 
|  | 363 <h5>Method GetTableName</h5> | 
|  | 364 | 
|  | 365 <% cs # | 
|  | 366 protected virtual string GetTableName(Type type) | 
|  | 367 { | 
|  | 368     // ... | 
|  | 369     return type.Name; | 
|  | 370 } | 
|  | 371 %> | 
|  | 372 | 
|  | 373 <p class='j'> | 
|  | 374 By default, the table name is the associated object type name (<i>Person</i> in our examples). | 
|  | 375 There are two ways to associate an object type with an accessor. By providing generic parameter: | 
|  | 376 </p> | 
|  | 377  <% cs # | 
|  | 378 public abstract class PersonAccessor : DataAccessor<Person> | 
|  | 379 { | 
|  | 380 } | 
|  | 381 %> | 
|  | 382 | 
|  | 383 <p class='j'> | 
|  | 384 And by the <b>ObjectType</b> attribute: | 
|  | 385 </p> | 
|  | 386 <% cs # | 
|  | 387 [ObjectType(typeof(Person))] | 
|  | 388 public abstract class PersonAccessor : DataAccessor | 
|  | 389 { | 
|  | 390 } | 
|  | 391 %> | 
|  | 392 | 
|  | 393 <p class='j'> | 
|  | 394 If you want to have different table and type names in your application, you may override the <b>GetTableName</b> method: | 
|  | 395 </p> | 
|  | 396 <% cs # | 
|  | 397 public abstract class OracleDataAccessor<T,A> : DataAccessor<T,A> | 
|  | 398 	where A : DataAccessor<T,A> | 
|  | 399 { | 
|  | 400 	protected override string GetTableName(Type type) | 
|  | 401 	{ | 
|  | 402 		return base.GetTableName(type).ToUpper(); | 
|  | 403 	} | 
|  | 404 } | 
|  | 405 %> | 
|  | 406 | 
|  | 407 <h5>TableNameAttribute</h5> | 
|  | 408 | 
|  | 409 <p class='j'> | 
|  | 410 Also, you can change the table name for a particular object type by decorating this object | 
|  | 411 with the <b>TableNameAttribute</b> attribute: | 
|  | 412 </p> | 
|  | 413 <% cs # | 
|  | 414 [TableName("PERSON")] | 
|  | 415 public class Person | 
|  | 416 { | 
|  | 417 	public int    ID; | 
|  | 418 	public string FirstName; | 
|  | 419 	public string LastName; | 
|  | 420 } | 
|  | 421 %> | 
|  | 422 | 
|  | 423 <h5>ActionNameAttribute</h5> | 
|  | 424 | 
|  | 425 <p class='j'> | 
|  | 426 This attribute allows changing the action name. | 
|  | 427 </p> | 
|  | 428 <% cs # | 
|  | 429 public abstract class PersonAccessor : DataAccessor<Person, PersonAccessor> | 
|  | 430 { | 
|  | 431 	[ActionName("GetByID")] | 
|  | 432 	protected abstract IDataReader GetByIDInternal(DbManager db, int id); | 
|  | 433 | 
|  | 434 	public Person GetByID(int id) | 
|  | 435 	{ | 
|  | 436 		using (DbManager   db = GetDbManager()) | 
|  | 437 		using (IDataReader rd = GetByIDInternal(db, id)) | 
|  | 438 		{ | 
|  | 439 			Person p = new Person(); | 
|  | 440 | 
|  | 441 			// do something complicated. | 
|  | 442 | 
|  | 443 			return p; | 
|  | 444 		} | 
|  | 445 	} | 
|  | 446 } | 
|  | 447 %> | 
|  | 448 | 
|  | 449 <h5>ActionSprocNameAttribute</h5> | 
|  | 450 | 
|  | 451 <p class='j'> | 
|  | 452 This attribute associates the action name with a stored procedure name: | 
|  | 453 </p> | 
|  | 454 <% cs# | 
|  | 455 [ActionSprocName("Insert", sp_Person_Insert")] | 
|  | 456 public abstract class PersonAccessor : DataAccessor<Person, PersonAccessor> | 
|  | 457 { | 
|  | 458 	public abstract void Insert(Person p); | 
|  | 459 } | 
|  | 460 %> | 
|  | 461 | 
|  | 462 <p class='j'> | 
|  | 463 This attribute can be useful when you need to reassign a stored procedure name for a method defined in your base class. | 
|  | 464 </p> | 
|  | 465 | 
|  | 466 <h5>SprocNameAttribute</h5> | 
|  | 467 | 
|  | 468 <p class='j'> | 
|  | 469 The regular way to assign deferent from default sproc name for a method is the <b>SprocName</b> attribute. | 
|  | 470 </p> | 
|  | 471 <% cs # | 
|  | 472 public abstract class PersonAccessor : DataAccessor<Person, PersonAccessor> | 
|  | 473 { | 
|  | 474 	[SprocName("sp_Person_Insert")] | 
|  | 475 	public abstract void Insert(Person p); | 
|  | 476 } | 
|  | 477 %> | 
|  | 478 | 
|  | 479 <a name='DestinationAttribute'></a><h5>DestinationAttribute</h5> | 
|  | 480 | 
|  | 481 <p class='j'> | 
|  | 482 By default, the DataAccessor generator uses method's return value to determine which <i>Execute</i> method | 
|  | 483 should be used to perform the current operation. | 
|  | 484 The <b>DestinationAttribute</b> indicates that target object is a parameter decorated with this attribute: | 
|  | 485 </p> | 
|  | 486 <% cs # | 
|  | 487 public abstract class PersonAccessor : DataAccessor<Person, PersonAccessor> | 
|  | 488 { | 
|  | 489 	public abstract void GetAll([Destination] List<Person> list); | 
|  | 490 } | 
|  | 491 %> | 
|  | 492 | 
|  | 493 <h5>DirectionAttributes</h5> | 
|  | 494 | 
|  | 495 <p class='j'> | 
|  | 496 <i>DataAccessor</i> generator can map provided business object to stored | 
|  | 497 procedure parameters. <b>Direction</b> attributes allow controlling this process more precisely. | 
|  | 498 </p> | 
|  | 499 <% cs # | 
|  | 500 public abstract class PersonAccessor : DataAccessor<Person, PersonAccessor> | 
|  | 501 { | 
|  | 502 	public abstract void Insert( | 
|  | 503 		[Direction.Output("ID"), Direction.Ignore("LastName")] Person person); | 
|  | 504 } | 
|  | 505 %> | 
|  | 506 | 
|  | 507 <p class='j'> | 
|  | 508 In addition, BLToolkit provides two more direction attributes: | 
|  | 509 <b>Direction.InputOutputAttribute</b> and <b>Direction.ReturnValueAttribute</b>. | 
|  | 510 </p> | 
|  | 511 | 
|  | 512 <h5>DiscoverParametersAttribute</h5> | 
|  | 513 <p class='j'> | 
|  | 514 By default, BLToolkit expects method parameter names to match stored procedure | 
|  | 515 parameter names. The sequential order of parameters is not important in this | 
|  | 516 case. This attribute enforces BLToolkit to retrieve parameter information from | 
|  | 517 the sproc and to assign method parameters in the order they go. Parameter names | 
|  | 518 are ignored. | 
|  | 519 </p> | 
|  | 520 | 
|  | 521 <a name='FormatAttribute'></a><h5>FormatAttribute</h5> | 
|  | 522 | 
|  | 523 <p class='j'> | 
|  | 524 This attribute indicates that the specified parameter is used to construct the stored procedure name or SQL statement: | 
|  | 525 </p> | 
|  | 526 <% cs # | 
|  | 527 public abstract class PersonAccessor : DataAccessor<Person, PersonAccessor> | 
|  | 528 { | 
|  | 529 	[SqlQuery("SELECT {0} FROM {1} WHERE {2}")] | 
|  | 530 	public abstract List<string> GetStrings( | 
|  | 531 		[Format(0)] string fieldName, | 
|  | 532 		[Format(1)] string tableName, | 
|  | 533 		[Format(2)] string whereClause); | 
|  | 534 } | 
|  | 535 %> | 
|  | 536 | 
|  | 537 <h5>IndexAttribute</h5> | 
|  | 538 | 
|  | 539 <p class='j'> | 
|  | 540 If you want your method to return a dictionary, you will have to specify fields to build the dictionary key. | 
|  | 541 The Index attribute allows you to do that: | 
|  | 542 </p> | 
|  | 543 <% cs # | 
|  | 544 public abstract class PersonAccessor : DataAccessor<Person, PersonAccessor> | 
|  | 545 { | 
|  | 546 	[SqlQuery("SELECT * FROM Person")] | 
|  | 547 	[Index("ID")] | 
|  | 548 	public abstract Dictionary<int, Person>           SelectAll1(); | 
|  | 549 | 
|  | 550 	[SqlQuery("SELECT * FROM Person")] | 
|  | 551 	[Index("@PersonID", "LastName")] | 
|  | 552 	public abstract Dictionary<CompoundValue, Person> SelectAll2(); | 
|  | 553 } | 
|  | 554 %> | 
|  | 555 <p class='j'>Note: if your key has more than one field, the type of this key should be <b>CompoundValue</b>.</p> | 
|  | 556 <p class='j'>If the field name starts from '@' symbol, BLToolkit reads the field value from data source, | 
|  | 557 otherwise from an object property/field.</p> | 
|  | 558 | 
|  | 559 <h5>ParamNameAttribute</h5> | 
|  | 560 | 
|  | 561 <p class='j'> | 
|  | 562 By default, the method parameter name should match the stored procedure parameter name. | 
|  | 563 This attribute specifies the sproc parameter name explicitly. | 
|  | 564 </p> | 
|  | 565 <% cs # | 
|  | 566 public abstract class PersonAccessor : DataAccessor<Person, PersonAccessor> | 
|  | 567 { | 
|  | 568 	public abstract Person SelectByName( | 
|  | 569 		[ParamName("FirstName")] string name1, | 
|  | 570 		[ParamName("@LastName")] string name2); | 
|  | 571 } | 
|  | 572 %> | 
|  | 573 | 
|  | 574 <h5>ScalarFieldNameAttribute</h5> | 
|  | 575 | 
|  | 576 <p class='j'> | 
|  | 577 If your method returns a dictionary of scalar values, you will have to specify the name or index of the field | 
|  | 578 used to populate the scalar list. The <b>ScalarFieldName</b> attribute allows you to do that: | 
|  | 579 </p> | 
|  | 580 <% cs # | 
|  | 581 public abstract class PersonAccessor : DataAccessor<Person, PersonAccessor> | 
|  | 582 { | 
|  | 583 	[SqlQuery("SELECT * FROM Person")] | 
|  | 584 	[Index("@PersonID")] | 
|  | 585 	[ScalarFieldName("FirstName")] | 
|  | 586 	public abstract Dictionary<int, string>           SelectAll1(); | 
|  | 587 | 
|  | 588 	[SqlQuery("SELECT * FROM Person")] | 
|  | 589 	[Index("PersonID", "LastName")] | 
|  | 590 	[ScalarFieldName("FirstName")] | 
|  | 591 	public abstract Dictionary<CompoundValue, string> SelectAll2(); | 
|  | 592 } | 
|  | 593 %> | 
|  | 594 | 
|  | 595 <h5>ScalarSourceAttribute</h5> | 
|  | 596 | 
|  | 597 <p class='j'> | 
|  | 598 If a method returns a scalar value, this attribute can be used to specify how database returns this value. | 
|  | 599 The <b>ScalarSource</b> attribute take a parameter of the <b>ScalarSourceType</b> type: | 
|  | 600 </p> | 
|  | 601 | 
|  | 602 <table class='data'> | 
|  | 603 <tr><th>ScalarSourceType</th><th>Description</th></tr> | 
|  | 604 <tr><td>DataReader</td><td>Calls the <b>DbManager.ExecuteReader</b> method, and then calls <b>IDataReader.GetValue</b> method to read the value.</td></tr> | 
|  | 605 <tr><td>OutputParameter</td><td>Calls the <b>DbManager.ExecuteNonQuery</b> method, and then reads value from the <b>IDbDataParameter.Value</b> property.</td></tr> | 
|  | 606 <tr><td>ReturnValue</td><td>Calls the <b>DbManager.ExecuteNonQuery</b> method, and then reads return value from command parameter collection.</td></tr> | 
|  | 607 <tr><td>AffectedRows</td><td>Calls the <b>DbManager.ExecuteNonQuery</b> method, and then returns its return value.</td></tr> | 
|  | 608 </table> | 
|  | 609 | 
|  | 610 <h5>SqlQueryAttribute</h5> | 
|  | 611 | 
|  | 612 <p class='j'> | 
|  | 613 This attribute allows specifying SQL statement. | 
|  | 614 </p> | 
|  | 615 <% cs # public abstract class PersonAccessor : DataAccessor<Person, PersonAccessor> | 
|  | 616 { | 
|  | 617     [SqlQuery("SELECT * FROM Person WHERE PersonID = @id")] | 
|  | 618     public abstract Person GetByID(int @id); | 
|  | 619 } | 
|  | 620 %> | 
|  | 621 | 
|  | 622 <h4>Conclusion</h4> | 
|  | 623 | 
|  | 624 <p class='j'> | 
|  | 625 I hope this brief tutorial demonstrates one of the simplest, quickest and | 
|  | 626 most low-maintenance ways to develop your data access layer. In addition, you | 
|  | 627 will get one more benefit, which is incredible object mapping performance. But | 
|  | 628 that is a topic we will discuss later. | 
|  | 629 </p> |