Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 52 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
52
Dung lượng
765,37 KB
Nội dung
How It Works In this program, you use a scalar query and two statements, storing the SQL in three string variables: // define scalar query string sqlqry = @" select count(*) from employees "; // define insert statement string sqlins = @" insert into employees ( firstname, lastname ) values('Zachariah', 'Zinn') "; // define delete statement CHAPTER 6 ■ INTRODUCING COMMANDS 131 Figure 6-6. Executing statements 777Xch06final.qxd 11/18/06 3:24 PM Page 131 string sqldel = @" delete from employees where firstname = 'Zachariah' and lastname = 'Zinn' "; Then you create two commands. The first is cmdqry, which encapsulates the scalar query to count the rows in the Employees table. You use this command several times to monitor the number of rows as you insert and delete employees. The second is cmdnon, which you use twice, first to insert a row, then to delete the same row. You initially set its CommandText to the INSERT statement SQL SqlCommand cmdnon = new SqlCommand(sqlins, conn); and later reset it to the DELETE statement SQL cmdnon.CommandText = sqldel; executing the SQL statements with two calls to cmdnon.ExecuteNonQuery(); ExecuteNonQuery() returns an int indicating how many rows are affected by the command. Since y ou want to display the number of affected rows, you put the call to ExecuteNonQuery() within a call to Console.WriteLine(). You use ExecuteScalar() to display the number of rows, before and after the INSERT and DELETE operations: Console.WriteLine("After INSERT: Number of Employees is: {0}", selectCommand.ExecuteScalar() ); N ote that both cmdqry and cmdnon ar e SqlCommand objects . The difference between sub- mitting quer ies and statements is the method y ou use to submit them. ■Note With ExecuteNonQuery(), you can submit virtually any SQL statement, including Data Definition Langua ge (DDL) statements to create and drop database objects such as tables and indexes. We’ll create tables in Chapter 11, using SSMSE, because that’s how they’re typically created, but the SQL you learn there can be submitted from a C# program with ExecuteNonQuery(). CHAPTER 6 ■ INTRODUCING COMMANDS132 777Xch06final.qxd 11/18/06 3:24 PM Page 132 Command Parameters When you insert the new row into Employees, you hard-code the values. Although this is perfectly valid SQL, it’s something you almost never want (or need) to do. You need to be able to store whatever values are appropriate at any given time. There are two approaches to doing this. Both are reasonable, but one is far more efficient than the other. The less efficient alternative is to dynamically build a SQL statement, producing a string that contains all the necessary information in the CommandText property. For example, you could do something like this: string fname = "Zachariah"; string lname = "Zinn"; string vals = "('" + fname + "'," + "'" + lname +"')" ; string sqlins = @" insert into employees ( firstname, lastname ) values" + vals ; You’d then assign sqlins to some command’s CommandText before executing the statement. ■Note Of course, we’re using fname and lname simply as rudimentary sources of data. Data most likely comes from some dynamic input source and involves many rows over time, but the technique is nonetheless the same: building a SQL string from a combination of hard-coded SQL keywords and values contained in variables. A much better way to handle this is with command par ameters . A command par ame - ter is a placeholder in the command text wher e a v alue will be substituted. In SQL Server, named par ameters ar e used. They begin with @ follo w ed b y the parameter name with no inter v ening space . So, in the following INSERT statement, @MyName and @MyNumber ar e both par ameters: INSERT INTO MyTable VALUES (@MyName, @MyNumber) CHAPTER 6 ■ INTRODUCING COMMANDS 133 777Xch06final.qxd 11/18/06 3:24 PM Page 133 ■Note Some data providers use the standard SQL parameter marker, a question mark (?), instead of named parameters. Command parameters have several advantages: • The mapping between the variables and where they’re used in SQL is clearer. • Parameters let you use the type definitions that are specific to a particular ADO.NET data provider to ensure that your variables are mapped to the correct SQL data types. • Parameters let you use the Prepare method, which can make your code run faster because SQL Server parses the SQL in a “prepared” command only the first time it’s executed. Subsequent executions run the same SQL, changing only parameter values. • Parameters are used extensively in other programming techniques, such as stored procedures (see Chapter 13) and working with irregular data (see Chapter 18). Try It Out: Using Command Parameters Follow these steps: 1. Add a new C# Console Application project named CommandParameters to your Chapter06 solution. Rename Program.cs to CommandParameters.cs. 2. Replace the code in CommandParameters.cs with the code in Listing 6-5. This is a variation of Listing 6-4, with salient changes highlighted. Listing 6-5. CommandParameters.cs using System; using System.Data; using System.Data.SqlClient; namespace Chapter06 { class CommandParameters { static void Main() CHAPTER 6 ■ INTRODUCING COMMANDS134 777Xch06final.qxd 11/18/06 3:24 PM Page 134 { // set up rudimentary data string fname = "Zachariah"; string lname = "Zinn"; // create connection SqlConnection conn = new SqlConnection(@" server = .\sqlexpress; integrated security = true; database = northwind "); // define scalar query string sqlqry = @" select count(*) from employees "; // define insert statement string sqlins = @" insert into employees ( firstname, lastname ) values(@fname, @lname) "; // define delete statement string sqldel = @" delete from employees where firstname = @fname and lastname = @lname "; CHAPTER 6 ■ INTRODUCING COMMANDS 135 777Xch06final.qxd 11/18/06 3:24 PM Page 135 // create commands SqlCommand cmdqry = new SqlCommand(sqlqry, conn); SqlCommand cmdnon = new SqlCommand(sqlins, conn); // add parameters to the command for statements cmdnon.Parameters.Add("@fname", SqlDbType.NVarChar, 10); cmdnon.Parameters.Add("@fname", SqlDbType.NVarChar, 20); try { // open connection conn.Open(); // execute query to get number of employees Console.WriteLine( "Before INSERT: Number of employees {0}\n" , cmdqry.ExecuteScalar() ); // execute nonquery to insert an employee cmdnon.Parameters["@fname"].Value = fname; cmdnon.Parameters["@lname"].Value = lname; Console.WriteLine( "Executing statement {0}" , cmdnon.CommandText ); cmdnon.ExecuteNonQuery(); Console.WriteLine( "After INSERT: Number of employees {0}\n" , cmdqry.ExecuteScalar() ); // execute nonquery to delete an employee cmdnon.CommandText = sqldel; Console.WriteLine( "Executing statement {0}" , cmdnon.CommandText ); CHAPTER 6 ■ INTRODUCING COMMANDS136 777Xch06final.qxd 11/18/06 3:24 PM Page 136 cmdnon.ExecuteNonQuery(); Console.WriteLine( "After DELETE: Number of employees {0}\n" , cmdqry.ExecuteScalar() ); } catch (SqlException ex) { Console.WriteLine(ex.ToString()); } finally { conn.Close(); Console.WriteLine("Connection Closed."); } } } } 3. Make it the startup project, and then run it with Ctrl+F5. You should see the result shown in Figure 6-7. How It Works First, you set up the sample data: // set up rudimentary data CHAPTER 6 ■ INTRODUCING COMMANDS 137 Figure 6-7. Using command parameters 777Xch06final.qxd 11/18/06 3:24 PM Page 137 string fname = "Zachariah"; string lname = "Zinn"; Then you add two parameters, @fname and @lname, to the Parameters collection property of the command you want to parameterize: // create commands SqlCommand cmdqry = new SqlCommand(sqlqry, conn); SqlCommand cmdnon = new SqlCommand(sqlins, conn); // add parameters to the command for statements cmdnon.Parameters.Add("@fname", SqlDbType.NVarChar, 10); cmdnon.Parameters.Add("@fname", SqlDbType.NVarChar, 20); Note that you provide the parameter names as strings, then specify the data types of the columns you expect to use them with. The SqlDbType enumeration contains a member for every SQL Server data type except cursor and table, which C# programs can’t directly use. The Add method is overloaded. Since nvarchar requires you to specify its maximum length, you include that as the third argument. Finally, you set the parameter values before executing the command: // execute nonquery to insert an employee cmdnon.Parameters["@fname"].Value = fname; cmdnon.Parameters["@lname"].Value = lname; ■Note The same command, cmdnon, is used to execute both the INSERT and DELETE statements. The parameter values don’t change, even though the SQL in CommandText does. The Parameters collection is the source of parameter values for whatever SQL is in CommandText. The SQL doesn’t have to use all or even any of the parameters, but it cannot use any parameters not in the command’s Parameters collection. N otice in F igure 6-7 that when you display the SQL in CommandText, y ou see the par ameter names r ather than their values. Values are substituted for parameters when the SQL is submitted to the database server, not when the values are assigned to the members of the Parameters collection. The Prepare Method When y ou expect to execute a par ameterized command multiple times, you should pr epar e it with the Prepare method. The syntax is simple: CHAPTER 6 ■ INTRODUCING COMMANDS138 777Xch06final.qxd 11/18/06 3:24 PM Page 138 command.Prepare(); You can execute it any time after the parameters have been added to the command and before the command is executed. Prepare() avoids SQL parsing overhead. The query or statement associated with the command is parsed only on first execution. After that, the cached SQL is executed, changing only parameter values. You never have to prepare any commands, but it’s always the best practice to do this if you expect to execute a command multiple times. ■Note If you change its CommandText after you prepare a command, you must prepare the command again to gain the advantage of prepared SQL. For a command to stay prepared, only parameter values can change between command executions. You can use Prepare() even if you only execute a command once, but it’s a waste of your time and the computer’s. For example, you could change CommandParameters.cs by adding the following line in bold: // execute nonquery to insert an employee cmdnon.Parameters["@fname"].Value = fname; cmdnon.Parameters["@lname"].Value = lname; Console.WriteLine( "Executing statement {0}" , cmdnon.CommandText ); cmdnon.Prepare(); cmdnon.ExecuteNonQuery(); Console.WriteLine( "After INSERT: Number of employees {0}\n" , cmdqry.ExecuteScalar() ); I t would still r un as expected, but now you’ve added an unnecessary call to Prepare(). F ur ther, the prepared command is discarded when you change the CommandText befor e per forming the DELETE cmdnon.CommandText = sqldel; CHAPTER 6 ■ INTRODUCING COMMANDS 139 777Xch06final.qxd 11/18/06 3:24 PM Page 139 because the new SQL statement is different (though it still uses the same parameters and they stay in effect). ■Tip If you prepare commands, use them for only one SQL query or statement. Create as many command objects as you need to prepare. Summary In this chapter, we covered quite a few things: • What an ADO.NET command is and does • How to create a command • How to associate a command with a connection • How to set command text • How to use ExecuteScalar() for queries that return single values • How to use ExecuteReader() to process result sets • How to use ExecuteNonQuery() for statements • What command parameters are and how to use them • How to use the Prepare method In the next chapter, we’ll look at data readers. CHAPTER 6 ■ INTRODUCING COMMANDS140 777Xch06final.qxd 11/18/06 3:24 PM Page 140 [...]... number to the reader to retrieve values (just as you’d specify an index for an array) Since in this case you choose a single column from the Customers table while querying the database, only the “zeroth” indexer is accessible, so you hard-code the index as rdr[0] To use the connection for another purpose or to run another query on the database, it’s important to call the Close method of SqlDataReader to. ..777Xch07final.qxd 11/18/06 2 :46 PM CHAPTER Page 141 7 sss Introducing Data Readers I n Chapter 4, you used data readers to retrieve data from a multirow result set In this chapter, we’ll look at data readers in more detail You’ll see how they’re used and their importance in ADO.NET programming In particular, you’ll see how to use data readers to do the following: • Retrieve query results... Using Ordinal Indexers You use an ordinal indexer to retrieve column data from the result set Let’s learn more about ordinal indexers The code rdr[0] is a reference to the data reader’s Item property, and returns the value in the column specified for the current row The value is returned as an object 145 777Xch07final.qxd 146 11/18/06 2 :46 PM Page 146 CHAPTER 7 s INTRODUCING DATA READERS Try It Out:... Since the returned value is an object, you need to explicitly convert the value to a string so that you can use the PadLeft method to format the output: 777Xch07final.qxd 11/18/06 2 :46 PM Page 149 CHAPTER 7 s INTRODUCING DATA READERS // loop through result set while (rdr.Read()) { Console.WriteLine(" {0} | {1}", rdr[0].ToString().PadLeft(25), rdr[1].ToString().PadLeft(20)); } After processing all rows... productname, unitprice, unitsinstock, discontinued from products "; We chose these columns to deal with different kinds of data types and to show how to use relevant typed accessors to obtain the correct results: // fetch data while (rdr.Read()) { Console.WriteLine( "{0}\t {1}\t\t {2}\t {3}", // nvarchar rdr.GetString(0).PadRight(30), 155 777Xch07final.qxd 156 11/18/06 2 :46 PM Page 156 CHAPTER 7 s INTRODUCING... metadata 163 777Xch07final.qxd 1 64 11/18/06 2 :46 PM Page 1 64 CHAPTER 7 s INTRODUCING DATA READERS How It Works This code is a bit different from what you’ve written earlier When the call to the GetSchemaTable method is made, a populated instance of a data table is returned: // store Employees schema in a data table DataTable schema = rdr.GetSchemaTable(); You can use a data table to represent a complete table... set 141 777Xch07final.qxd 142 11/18/06 2 :46 PM Page 142 CHAPTER 7 s INTRODUCING DATA READERS You can’t instantiate a data reader directly; instead, you create one with the ExecuteReader method of a command For example, assuming cmd is a SqlClient command object for a query, here’s how to create a SqlClient data reader: SqlDataReader rdr = cmd.ExecuteReader(); You can now use this data reader to access... Types Column Name Data Type Length Allow Nulls? ProductID (unique) int 4 No ProductName nvarchar 40 No SupplierID int 4 Yes CategoryID int 4 Yes QuantityPerUnit nvarchar 20 Yes UnitPrice money 8 Yes UnitsInStock smallint 2 Yes UnitsOnOrder smallint 2 Yes ReorderLevel smallint 2 Yes Discontinued bit 1 No 777Xch07final.qxd 11/18/06 2 :46 PM Page 153 CHAPTER 7 s INTRODUCING DATA READERS Try It Out: Using... everything seems to be going fine—what now? The next sensible thing to do would be to retrieve the rows and process them Try It Out: Looping Through a Result Set The following steps show how to use a SqlDataReader to loop through a result set and retrieve rows: 1 Create a new Console Application project named Chapter07 When Solution Explorer opens, save the solution 2 Rename the Chapter07 project to DataLooper... through result set while (rdr.Read()) { Console.WriteLine(" {0} | {1}", rdr[0].ToString().PadLeft(25), rdr[1].ToString().PadLeft(20)); } // close reader rdr.Close(); } catch(Exception e) { Console.WriteLine("Error Occurred: " + e); } finally { // close connection conn.Close(); } } } } 147 777Xch07final.qxd 148 11/18/06 2 :46 PM Page 148 CHAPTER 7 s INTRODUCING DATA READERS 3 Make this the startup project, . INTRODUCING DATA READERS 144 Figure 7-1. Looping through a result set 777Xch07final.qxd 11/18/06 2 :46 PM Page 144 ExecuteReader() doesn’t just create a data reader, it sends the SQL to the connec- tion. are and how to use them • How to use the Prepare method In the next chapter, we’ll look at data readers. CHAPTER 6 ■ INTRODUCING COMMANDS 140 777Xch06final.qxd 11/18/06 3: 24 PM Page 140 Introducing. something you almost never want (or need) to do. You need to be able to store whatever values are appropriate at any given time. There are two approaches to doing this. Both are reasonable, but