I have added some data from the local database to a List, and now I need to show the values this List has inside a dropdownlist. The List contains the following data:
Java
.net
JavaScript
Ruby
Python
Method:
public List<string> DisplayTopicNames()
{
// declare the connection string
string database = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|/Forum.accdb;Persist Security Info=True";
// Initialise the connection
OleDbConnection myConn = new OleDbConnection(database);
//Query
string queryStr = "SELECT TopicName FROM Topics";
// Create a command object
OleDbCommand myCommand = new OleDbCommand(queryStr, myConn);
// Open the connection
myCommand.Connection.Open();
// Execute the command
OleDbDataReader myDataReader = myCommand.ExecuteReader();
// Extract the results
List<string> topicNames = new List<string>();
while (myDataReader.Read())
{
topicNames.Add(myDataReader.GetValue(0).ToString());
}
// close the connection
myCommand.Connection.Close();
return topicNames;
}
}
When I return the above method on its own it works fine and all the values are there but When I use the following code to add this List to the dropdownlist it only shows "j" "a" "v" "a" which is very strange.
DropDownList1.DataSource = dt.DisplayTopicNames();
DropDownList1.DataBind();
Instead of:
topicNames.Add(myDataReader.GetValue(0).ToString());
try this:
topicNames.Add(myDataReader["TopicName"].ToString());
Related
I have a combobox on a windows form that I fill with a list of names. At the moment I have the following code inside the Form class and it works fine
// This section opens a connection to the database, selects all the portfolio names that have an "in Use" value of 1, and then
// fills Combo Box 2 with the values.
SqlConnection myConnection = new SqlConnection(#"Data Source = (LocalDB)\MSSQLLocalDB; AttachDbFilename = ""C:\Users\Nick\Documents\Investments 4.mdf""; Integrated Security = True; Connect Timeout = 30");
myConnection.Open();
SqlCommand myCommand2 = new SqlCommand();
myCommand2.Connection = myConnection;
myCommand2.CommandText = "SELECT Portfolio_Name FROM Dbo.Name WHERE In_use = 1";
SqlDataReader myReader2 = myCommand2.ExecuteReader();
while (myReader2.Read())
{
comboBox2.Items.Add(myReader2[0]);
}
myConnection.Close();
I would like to be able to extract this into a separate method, and put it into a separate class for general utility methods. However, I'm stuck on a really simple issue. When I put the code into a class, I need to be able to tell it which combox box I want to fill, and I can't figure out how to pass in that information. Sorry if the answer is obvious, but any help would be gratefully received.
Thanks!
Well, if you want to extract, then extract:
// Let's extract a class: it should provide us standard cursors,
// e.g. Protfolio Names
public static class MyData {
// Let's enumerate items returned
public static IEnumerable<string> PortfolioNames() {
// Wrap IDisposable into using
//TODO: move Connection String into a separated method/property
using (SqlConnection con = new SqlConnection(/*connection string here*/)) {
con.Open();
// Make sql readable
//DONE: when presenting something to user, sort it (order by) esp. strings
string sql =
#" select Portfolio_Name
from Dbo.Name
where In_use = 1
order by Portfolio_Name";
// Wrap IDisposable into using
using (SqlCommand q = new SqlCommand(sql, con)) {
// Wrap IDisposable into using
using (var reader = q.ExecuteReader()) {
while (reader.Read())
yield return Convert.ToString(reader[0]);
}
}
}
}
}
And then use
// Adding items in one after one manner is often a bad idea:
// it makes UI repaint each time you add an item and cause blinking.
// Let's fill the ComboBox in one go via AddRange
comboBox2.Items.AddRange(MyData.PortfolioNames().ToArray());
You can use a helper class names Portfolio for data access. The method GetNames does not require a ComboBox instance. This increases the chance that you can reuse the method in another context.
public static class Portfolio
{
public static IList<string> GetNames()
{
SqlConnection myConnection = new SqlConnection(#"Data Source = (LocalDB)\MSSQLLocalDB; AttachDbFilename = ""C:\Users\Nick\Documents\Investments 4.mdf""; Integrated Security = True; Connect Timeout = 30");
myConnection.Open();
SqlCommand myCommand2 = new SqlCommand();
myCommand2.Connection = myConnection;
myCommand2.CommandText = "SELECT Portfolio_Name FROM Dbo.Name WHERE In_use = 1";
SqlDataReader myReader2 = myCommand2.ExecuteReader();
var portfolioNames = new List<string>();
while (myReader2.Read())
{
portfolioNames.Add(myReader2[0]);
}
myConnection.Close();
return portfolioNames;
}
}
Then in your Form you can do something like this:
var names = Portfolio.GetNames();
foreach (var name in names)
{
combobox2.Items.Add(name);
}
It is so simple:
public class MyUtility
{
public static void FillComboBox(System.Windows.Forms.ComboBox comboBox)
{
//comboBox.Items.Clear(); //enable this line if required
using (SqlConnection myConnection = new SqlConnection(#"Data Source = (LocalDB)\MSSQLLocalDB; AttachDbFilename = ""C:\Users\Nick\Documents\Investments 4.mdf""; Integrated Security = True; Connect Timeout = 30"))
{
myConnection.Open();
using (SqlCommand myCommand2 = new SqlCommand())
{
myCommand2.Connection = myConnection;
myCommand2.CommandText = "SELECT Portfolio_Name FROM Dbo.Name WHERE In_use = 1";
using (SqlDataReader myReader2 = myCommand2.ExecuteReader())
{
while (myReader2.Read())
{
comboBox.Items.Add(myReader2[0]);
}
}
}
//myConnection.Close(); //not required inside using block
}
}
}
you may use other methods to get connection string (e.g. from config file).
The usage is so simple, no extra code required:
MyUtility.FillComboBox(comboBox2);
Trying to set up a connection to my local SQL Server Express instance so that I can display columns in a listbox. Th build runs fine and I can't see errors, but there is no data in the listbox. I have tested the query and that is fine. I am using NT Authentication to the database. Any ideas where I might have gone wrong?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void customers_SelectedIndexChanged(object sender, EventArgs e)
{
string commstring = "Driver ={SQL Server}; Server = DESKTOP-5T4MHHR\\SQLEXPRESS; Database = AdventureWorks2014; Trusted_Connection = Yes;";
string connstring = "SELECT FirstName, LastName FROM Person.Person";
SqlDataAdapter customerDataAdapater = new SqlDataAdapter(commstring, connstring);
DataSet customerDataSet = new DataSet();
customerDataAdapater.Fill(customerDataSet, "Person.Person");
DataTable customerDataTable = new DataTable();
customerDataTable = customerDataSet.Tables[0];
foreach (DataRow dataRow in customerDataTable.Rows)
{
customers.Items.Add(dataRow["FirstName"] + " (" + dataRow["LastName"] + ")");
}
}
}
I tested your code in a sample project here and I realized you passed the parameters to SqlDataAdapter constructor in a wrong order.
After changing the follow line:
SqlDataAdapter customerDataAdapater = new SqlDataAdapter(commstring, connstring);
by
SqlDataAdapter customerDataAdapater = new SqlDataAdapter(connstring, commstring);
the listbox was filled successfully.
Your connection string seems weird.....
Could you try using just this:
string commstring = "Server=DESKTOP-5T4MHHR\\SQLEXPRESS;Database=AdventureWorks2014;Trusted_Connection=Yes;";
Also: why are you first creating a DataSet, filling in a single set of data, and then extracting a DataTable from it?? This is unnecessarily complicated code - just use this instead:
SqlDataAdapter customerDataAdapater = new SqlDataAdapter(commstring, connstring);
// if you only ever need *one* set of data - just use a DataTable directly!
DataTable customerDataTable = new DataTable();
// Fill DataTable with the data from the query
customerDataAdapater.Fill(customerDataTable);
Update: I would really rewrite your code to something like this:
// create a separate class - call it whatever you like
public class DataProvider
{
// define a method to provide that data to you
public List<string> GetPeople()
{
// define connection string (I'd really load that from CONFIG, in real world)
string connstring = "Server=MSEDTOP;Database=AdventureWorks2014;Trusted_Connection=Yes;";
// define your query
string query = "SELECT FirstName, LastName FROM Person.Person";
// prepare a variable to hold the results
List<string> entries = new List<string>();
// put your SqlConnection and SqlCommand into "using" blocks
using (SqlConnection conn = new SqlConnection(connstring))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
conn.Open();
// iterate over the results using a SqlDataReader
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
// get first and last name from current row of query
string firstName = rdr.GetFieldValue<string>(0);
string lastName = rdr.GetFieldValue<string>(1);
// add entry to result list
entries.Add(firstName + " " + lastName);
}
rdr.Close();
}
conn.Close();
}
// return the results
return entries;
}
}
And in your code-behind, you only need to do something like this:
protected override void OnLoad(.....)
{
if (!IsPostback)
{
List<string> people = new DataProvider().GetPeople();
customers.DataSource = people;
customers.DataBind();
}
}
but I still don't understand what you were trying to when the SelectedIndexChanged event happens.....
I am trying to populate a group of labels in a C# windows form with some values that are in a certain attribute (PlayerName) in a database that I have in access.
Currently the only code I have is:
OleDbConnection connection = new OleDbConnection(CONNECTION STRING HERE);
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
command.CommandText = "SELECT PlayerName FROM [TotalPlayerName] WHERE Team = 1 AND SportID = " + Form1.IDNumber;
I need a list or array that holds these values so I can use them to populate the labels, but I am unaware of how to do this.
You need to call ExecuteReader to obtain a data reader and then loop through the rows of the result set like this:
List<string> result = new List<string>();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
result.Add(reader.GetString(0));
}
}
Before you do this, don't forget to open the connection like this:
connection.Open();
There are a couple of things here..... for sake of best practice well its more standard practice... as I like to say!
Use USING as this cleans up after connection.. see here for great examples in a "using" block is a SqlConnection closed on return or exception?
using (OdbcDataReader DbReader = DbCommand.ExecuteReader())
{
int fCount = DbReader.FieldCount;
while (DbReader.Read())
{
Label1 = DbReader.GetString(0);
Label2 = DbReader.GetString(1);
Label3 = DbReader.GetString(2);
Label4 = DbReader.GetString(3);
for (int i = 0; i < fCount; i++)
{
String col = DbReader.GetString(i);
Console.Write(col + ":");
}
Console.WriteLine();
}
}
NB your SQL only return 1 field /String at the moment
while reading the data fill the list like
List<string> players = new List<string>();
OleDbDataReader rdr = command.ExecuteReader();
While(rdr.Read())
{
players.Add(rdr["PlayerName"].ToString());
}
You need to create a OleDbReader object to read the response from the query. You will also need to create a List to store the data Something like this:
List<string> playerNameList = new List<string>();
using (OleDbReader r = command.ExecuteReader())
{
while(reader.Read())
{
playerNameList.Add(reader.GetString(0));
}
}
One option might be using OleDbDataAdapter to fill a DataTable those values that returns your query;
var dt = new DataTable();
using(var da = new OleDbDataAdapter(command))
{
da.Fill(dt);
}
And since your query return one column, you can use AsEnumerable to that datatable to get them as a string like;
List<string> list = dt.AsEnumerable()
.Select(r => r.Field<string>("PlayerName"))
.ToList();
You can read: Queries in LINQ to DataSet
By the way, you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
Also use using statement to dispose your connection and command automatically as I did for OleDbDataAdapter in my example.
I have a built a system which loads words from a database table but I need to add those words to a list of type "Choices" (the type that is needed for Grammar Building).
This is my code for requesting words to be retrieved from the database:
List<string> newWords = new List<string>();
newWords = LexicalOperations.WordLibrary().ToList();
Choices dbList = new Choices(); //Adding them to a Choice List
if (newWords.Count != 0)
{
foreach (string word in newWords)
{
dbList.Add(word.ToString());
}
}
else dbList.Add("Default");
This is my code of retrieving data from the table:
public class LexicalOperations
{
public static List<string> WordLibrary()
{
List<string> WordLibrary = new List<string>();
string conString = "Data Source=.;Initial Catalog=QABase;Integrated Security=True";
using (SqlConnection connection = new SqlConnection(conString))
{
connection.Open();
string sqlIns = "select WordList from NewWords";
SqlCommand cmd = new SqlCommand(sqlIns, connection);
SqlDataAdapter sda = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
sda.Fill(ds);
foreach (DataRow dr in ds.Tables[0].Rows)
{
WordLibrary.Add(dr[0].ToString());
}
}
return WordLibrary;
}
}
HOWEVER, This throws an exception: System.FormatException which also states the message:
FormatException was unhandled
Double-quoted string not valid.
This error is thrown when I build the choices list in a Speech Grammar Builder:
GrammarBuilder graBui = new GrammarBuilder(dbList);
Grammar Gra = new Grammar(graBui);
What am I doing wrong? What should be done in order to properly retrieve words from the database and add them to a Choice list?
The problem seems to be that your Grammar class cannot handle strings with double quotes.
So, the simplest way to remove the problem is to remove the double quotes by your input.
public class LexicalOperations
{
public static List<string> WordLibrary()
{
List<string> WordLibrary = new List<string>();
string conString = "Data Source=.;Initial Catalog=QABase;Integrated Security=True";
string sqlIns = "select WordList from NewWords";
using (SqlConnection connection = new SqlConnection(conString))
using (SqlCommand cmd = new SqlCommand(sqlIns, connection))
{
connection.Open();
using(SqlDataReader reader = cmd.ExecuteReader())
{
while(reader.Read())
{
string noQuotes = reader.GetString(0).Replace("\"", "");
WordLibrary.Add(noQuotes);
// In alternative you could also opt to not add a string with double quotes
// string noQuotes = reader.GetString(0);
// if(noQuotes.IndexOf("\"") < 0)
// WordLibrary.Add(noQuotes);
}
}
}
return WordLibrary;
}
}
Notice that I have also removed the SqlDataAdapter and the filling of a DataSet. In this context is useless and clearly hinders the performance because you are executing two loops. The first one is executed by the Framework to fill the DataSet, the second by your code to add the words to the List<string> variable
I am trying to display a column from my local database into a dropdown list. The problem is that I would need to split the data so that they are not displayed all in one line. I have used the ";" to separate the data and then using the split(";") method to split them. I have tried the code that I've wrote below but it's not working. Any help will be appreciated.
public string DisplayTopicNames()
{
string topicNames = "";
// declare the connection string
string database = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|/Forum.accdb;Persist Security Info=True";
// Initialise the connection
OleDbConnection myConn = new OleDbConnection(database);
//Query
string queryStr = "SELECT TopicName FROM Topics";
// Create a command object
OleDbCommand myCommand = new OleDbCommand(queryStr, myConn);
// Open the connection
myCommand.Connection.Open();
// Execute the command
OleDbDataReader myDataReader = myCommand.ExecuteReader();
// Extract the results
while (myDataReader.Read())
{
for (int i = 0; i < myDataReader.FieldCount; i++)
topicNames += myDataReader.GetValue(i) + " ";
topicNames += ";";
}
//Because the topicNames are seperated by a semicolon, I would have to split it using the split()
string[] splittedTopicNames = topicNames.Split(';');
// close the connection
myCommand.Connection.Close();
return Convert.ToString(splittedTopicNames);
}
You are returning just one column from the table.
There is no reason to use a for loop over a field count (it is always 1)
Instead you could use a List(Of String) to save the values returned by the rows found.
Then return this list to use as datasource for your DropDownList
List<string> topicNames = new List<string>();
// Extract the results
while (myDataReader.Read())
{
topicNames.Add(myDataReader.GetValue(0).ToString();
}
....
return topicNames;
However it is not clear if the field TopicName contains itself strings separated by semicolon.
In this case you could write:
List<string> topicNames = new List<string>();
// Extract the results
while (myDataReader.Read())
{
string[] topics = myDataReader.GetValue(0).ToString().Split(';')
topicNames.AddRange(topics);
}
...
return topicNames;
if you prefer to return an array of strings then it is just a matter to convert the list to an array
return topicNames.ToArray();
EDIT
Of course returning an array or a List(Of String) requires changes to the return value of your method
public List<string> DisplayTopicNames()
{
......
}
or
public string[] DisplayTopicNames()
{
......
}
if you still prefer to return a string separated by semicolons then change the return statement in this way
return string.Join(";", topicNames.ToArra());
Unless I've lost my mind, something like this should work:
while (myDataReader.Read())
{
for (int i = 0; i < myDataReader.FieldCount; i++)
ddl.Items.Add(myDataReader.GetValue(i))
}
where ddl is the name of your DropDownList. If your ddl isn't available here, then add them to a List<string> collection instead and return that. And then this code may now become irrelevant:
//Because the topicNames are seperated by a semicolon, I would have to split it using the split()
string[] splittedTopicNames = topicNames.Split(';');
// close the connection
myCommand.Connection.Close();
return Convert.ToString(splittedTopicNames);
but, on top of all this I want to restructure the code for you a little because you need to be leveraging things like using.
public string DisplayTopicNames()
{
string topicNames = "";
// declare the connection string
string database = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|/Forum.accdb;Persist Security Info=True";
// Initialise the connection
using (OleDbConnection myConn = new OleDbConnection(database))
{
myConn.Open();
// Create a command object
OleDbCommand myCommand = new OleDbCommand("SELECT TopicName FROM Topics", myConn);
// Execute the command
using (OleDbDataReader myDataReader = myCommand.ExecuteReader())
{
// Extract the results
while (myDataReader.Read())
{
for (int i = 0; i < myDataReader.FieldCount; i++)
{
ddl.Items.Add(myDataReader.GetValue(i));
}
}
}
}
// not sure anything needs returned here anymore
// but you'll have to evaluate that
return "";
}
The reason you want to leverage the using statement is to ensure that unmanaged resources that exist in the DataReader and Connection get disposed properly. When leaving the using statement it will automatically call Dispose on the object. This statement is only used for objects that implement IDisposable.
I think this should work:
public List<string> DisplayTopicNames()
{
List<string> topics = new List<string>();
// Initialise the connection
OleDbConnection conn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|/Forum.accdb;Persist Security Info=True");
OleDbCommand cmd = new OleDbCommand("SELECT TopicName FROM Topics");
using(conn)
using(cmd)
{
cmd.Connection.Open();
// Execute the command
using(OleDbDataReader myDataReader = cmd.ExecuteReader())
{
// Extract the results
while(myDataReader.Read())
{
topics.Add(myDataReader.GetValue(0).ToString());
}
}
}
return topics;
}