I have a Visual Basic application where I have a connection to a MS SQL database. I have code which defines a SqlDataReader, opens the connection, and executes the ExecuteReader() command. I use the following code to retrieve the data from the reader
While myDataReader.Read()
Session("menu_PEO") = myDataReader("menu_PEO")
Session("menu_Transfer") = myDataReader("menu_Transfer")
Session("menu_Loan") = myDataReader("menu_loan")
End While
menu_PEO, menu_Transfer, and menu_loan are 3 of the column headings in the data that the SQL returns.
I am now tasked with converting the code to c#. I have the following code in c# which works:
while (dataReader.Read())
{
dbMenuPEO = dataReader.GetString(1);
dbMenuTransfer = dataReader.GetString(2);
dbMenuLoan = dataReader.GetString(3);
}
Since my SQL is a SELECT *, I can not guarantee the order of the data being returned so I dont want to rely on specifying the instance of the GetString.
Is there a way in c# to specify the column name that I would like to retrieve similar to the way it works in Visual Basic?
Thanks!
CodePudding user response:
There are two ways to do this. The easy way is to use the named indexer:
dbMenuPEO = (string)dataReader["menu_PEO"];
Which is essentially the same as:
dbMenuPEO = (string)dataReader.GetValue(dataReader.GetOrdinal("menu_PEO"));
You can move the ordinal lookup outside of the loop, which is a bit more efficient. You can also use the the strongly-typed accessor which avoids the cast. This can be important when reading value types (int, dateTime, etc) as it avoid needing to box the value, which would happen with GetValue.
var menuPeoIdx = dataReader.GetOrdinal("menu_PEO");
while(dataReader.Read())
{
dbMenuPEO = dataReader.GetString(menuPeoIdx);
}
Generally, you should never use select *
in a production system. Always explicitly list the columns you want. The reason is that it allows the underlying tables to change without having to fix the consuming code, or over-selecting columns that you don't need. Select *
is a great tool for "exploring" a data set, but should only be used as a dev tool.
CodePudding user response:
I have code which defines a SqlDataReader, opens the connection, and executes the ExecuteReader()
And isn't it the most incredibly tedious code to have to write? Many people have thought this over the time and many things have been invented to relieve you of the tedium of it. MarkPflug's answer directly addresses your question, but just in case you aren't aware that there are significant productivity boosts available I'd like to introduce you to one of these technologies
Is there a way in c# to specify the column name that I would like to retrieve similar to the way it works in Visual Basic?
Here's a way to do it, in that when you do this you don't have to type it. It avoids typing the same thing again that you've already typed (twice - once for the variable name, once in the SQL)
Use the nuget package manager built into visual studio, to install Dapper
Then lets say you have a class that holds your data:
//C#
record DbMenu(string DbMenuPEO, string DbMenuTransfer, string DbMenuLoan);
'or VB, if you like that sort of thing
Class DbMenu
Public Property DbMenuPEO as String
Public Property DbMenuTransfer As String
Public Property DbMenuLoan As String
End Class
You can get Dapper to make your query, add any parameters, open your connection, download your data, fill up a list full of your classes, close the connection and return it.. all in one line of code:
//C#
using var conn = ... //code here that gets a connection; doesn't need to be open
var myListOfDbMenus = conn.Query<DbMenu>("SELECT * FROM ... ");
'VB
Using conn = ...
Dim myListOfDbMenus = conn.Query(Of DbMenu)("SELECT * FROM ... ");
End Using
The short short version is: your c# class properties should be named the same as your columns. If they aren't, it's easiest to use AS xyz
in the SQL to equalize the names. If you want to write a parameterized query, you provide @parameterNames
that are the same as the property names of an anonymous object you pass at the same time as your query:
var q = conn.Query<Type>("SELECT ... WHERE col = @val1", new {val1 = "hello" } );
If you like writing SQL and having that low level control/don't want to use an ORM like EF, then Dapper lets you carry on doing the SQL directly as you're doing, but takes away all the repetitive surrounding boilerplate
CodePudding user response:
The SQLDataReader
class exposes a set of instance methods that allow to retrieve the value of a field of a specific type, such as GetInt32()
and GetString()
, which can be used in combination with the GetOrdinal()
method
Example
dataReader.GetString(dataReader.GetOrdinal("YOUR FIELD NAME HERE"))