I'm struggling. I have query against my db that returns a single column of data and I need to set it as List. Here is what I am working with and I am getting an error about converting void to string.
public static void GetImportedFileList()
{
using (SQLiteConnection connect = new SQLiteConnection(#"Data Source=C:\Documents and Settings\js91162\Desktop\CMMData.db3"))
{
connect.Open();
using (SQLiteCommand fmd = connect.CreateCommand())
{
SQLiteCommand sqlComm = new SQLiteCommand(#"SELECT DISTINCT FileName FROM Import");
SQLiteDataReader r = sqlComm.ExecuteReader();
while (r.Read())
{
string FileNames = (string)r["FileName"];
List<string> ImportedFiles = new List<string>();
}
connect.Close();
}
}
}
Then later in application
List<string> ImportedFiles = GetImportedFileList() // Method that gets the list of files from the db
foreach (string file in files.Where(fl => !ImportedFiles.Contains(fl)))
public static List<string> GetImportedFileList(){
List<string> ImportedFiles = new List<string>();
using (SQLiteConnection connect = new SQLiteConnection(#"Data Source=C:\Documents and Settings\js91162\Desktop\CMMData.db3")){
connect.Open();
using (SQLiteCommand fmd = connect.CreateCommand()){
fmd.CommandText = #"SELECT DISTINCT FileName FROM Import";
fmd.CommandType = CommandType.Text;
SQLiteDataReader r = fmd.ExecuteReader();
while (r.Read()){
ImportedFiles.Add(Convert.ToString(r["FileName"]));
}
}
}
return ImportedFiles;
}
Things i've amended in your code:
Put ImportedFiles in scope of the entire method.
No need to call connect.Close(); since the connection object is wrapped in a using block.
Use Convert.ToString rather then (String) as the former will handle all datatype conversions to string. I came across this Here
Edit:
You were creating a new command object sqlComm instead of using fmd that was created by the connection object.
First of all your return type is void. You need to return a List. Another problem is that you initialize the list inside the loop, so in each pass of the loop you have a new list, and whatsmore, you do not add the string in the list. Your code should probably be more like:
public static List<string> GetImportedFileList()
{
List<string> ImportedFiles = new List<string>();
using (SQLiteConnection connect = new SQLiteConnection(#"Data Source=C:\Documents and Settings\js91162\Desktop\CMMData.db3"))
{
connect.Open();
using (SQLiteCommand fmd = connect.CreateCommand())
{
fmd.CommandText = #"SELECT DISTINCT FileName FROM Import";
SQLiteDataReader r = fmd.ExecuteReader();
while (r.Read())
{
string FileNames = (string)r["FileName"];
ImportedFiles.Add(FileNames);
}
connect.Close();
}
}
return ImportedFiles;
}
The error is about the return type of your method. You are returning void (public staticvoid) but then use it later as if it were returning a List<string>.
I think you intended the following method signature:
public static List<string> GetImportedFileList()
You already have a way to get the individual results, so to me it looks like you just need to:
Move the List<string> ImportedFiles = new List<string>(); outside the while loop.
Call ImportedFiles.Add(FileNames); inside the loop (after that string gets assigned).
return ImportedFiles at the end.
Change the return type to List<string>.
Related
I have a method that returns a string from a database based on what i pass to it. The method works but i need to display the result in a textbox on a form. But when i run it the result i keep getting is "System.Collections.Generic.List`1[System.String]". I cant work this out. I try looping through the interest variable with for loop but this doesn't work either.
var interest = GetValue2(tvp, connectionString); -- this is my method that returns a string
textBox2.Text = string.Join(", ", interest.ToString());
this returns "System.Collections.Generic.List`1[System.String]" to textbox2. Any ideas what im missing here? thanks
PART 2:
public static List<String> GetValue2(DataTable tvp, String connectionString)
{
List<String> items = new List<String>();
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand cmd = new SqlCommand("[dbo].[...]", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParameter = new SqlParameter();
tvpParameter.ParameterName = "#..";
tvpParameter.SqlDbType = System.Data.SqlDbType.Structured;
tvpParameter.Value = tvp;
tvpParameter.TypeName = "[dbo].[....]";
cmd.Parameters.Add(tvpParameter);
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine((String)rdr["id"]);
}
Console.ReadLine();
}
}
return items;
}
Could you share the GetValue2 method? Probably you are calling ToString() on List in that method and it that case the GetValue2 method returns
"System.Collections.Generic.List1[System.String]"
Example:
var test = new List<string>{"some text"};
test.ToString(); // returns System.Collections.Generic.List`1[System.String]
Update:
Because the method GetValue2 returns List<string> avoid calling .ToString() on interest
var interest = GetValue2(tvp, connectionString); // returns List<string>
textBox2.Text = string.Join(", ", interest);
There's also the issue of the List<string> items inside the GetValue2() not being populated.
Here's the corrected method:
public static List<String> GetValue2(DataTable tvp, String connectionString)
{
List<String> items = new List<String>();
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand cmd = new SqlCommand("[dbo].[...]", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParameter = new SqlParameter();
tvpParameter.ParameterName = "#..";
tvpParameter.SqlDbType = System.Data.SqlDbType.Structured;
tvpParameter.Value = tvp;
tvpParameter.TypeName = "[dbo].[....]";
cmd.Parameters.Add(tvpParameter);
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
items.Add((String)rdr["id"]);
}
}
}
return items;
}
I have put together the following method:
public static ArrayList DbQueryToArry()
{
string SqlCString = "connString";
SqlConnection connection = null;
ArrayList valuesList = new ArrayList();
connection = new SqlConnection(SqlCString);
connection.Open();
SqlCommand command = new SqlCommand("Select CLIENTNO, ACCOUNT_Purpose from audit.ACCOUNTS_AUDIT", connection);
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
valuesList.Add(Convert.ToString(reader[0]));
}
return valuesList;
}
I'd like to be able to run an assertion like this one:
var a = DbQueryToArry();
Assert.IsTrue(a.Contains("some value"));
Given reader [0]
valuesList.Add(Convert.ToString(reader[0]));
I only get the first column (CLIENTINFO) into the array and not the second (ACCOUNT_Purpose). How should I modify the code to get both ?
In addition, the returned values could be either a String or Int so would my current code version should be handling both ?
Thanks in advance.
If we switch from obsolete ArrayList to something like IEnumerable<T>:
public static IEnumerable<IDataRecord> DbQueryToArray(string sql) {
if (null == sql)
throw new ArgumentNullException(nameof(sql));
//TODO: do not hardcode connetcion string but read it (say, from Settings)
string SqlCString = "connString";
//DONE: Wrap IDisposable into using
using (SqlConnection connection = new SqlConnection(SqlCString)) {
connection.Open();
//DONE: Wrap IDisposable into using
using (SqlCommand command = new SqlCommand(sql, connection)) {
//DONE: Wrap IDisposable into using
using (SqlDataReader reader = command.ExecuteReader()) {
while (reader.Read()) {
yield return reader as IDataRecord;
}
}
}
}
}
then you can use Linq in order to query the result:
var a = DbQueryToArray("Select CLIENTNO, ACCOUNT_Purpose from audit.ACCOUNTS_AUDIT");
Assert.IsTrue(a.Any(record =>
Convert.ToString(record["CLIENTNO"]) == "some value"));
Assert.IsTrue(a.Any(record =>
Convert.ToString(record["ACCOUNT_Purpose"]) == "some other value"));
If you don't want execute query several times, you can materialize the results:
var a = DbQueryToArray("Select CLIENTNO, ACCOUNT_Purpose from audit.ACCOUNTS_AUDIT")
.ToList();
Assert.IsTrue(a.Any(record => Convert.ToString(record[0]) == "some value"));
Assert.IsTrue(a.Any(record => Convert.ToString(record[1]) == "some other value"));
Finally (see comments below), if we want to test if any field in any record has the value:
var a = DbQueryToArray("Select CLIENTNO, ACCOUNT_Purpose from audit.ACCOUNTS_AUDIT")
.SelectMany(line => {
// Flatten the cursor into IEnumerable<String>
string[] result = new string[line.FieldCount];
for (int i = 0; i < result.Length; ++i)
result[i] = Convert.ToString(line[i]);
return result;
});
a.Any(item => item == "some value");
It is because you only read the first value of the reader. Reader.Read() read each row one by one and Convert.ToString(reader[0])) means that you want to read the first column as string.
That's cause you are getting only the first column. You can do something like below by specifying the column name
while (reader.Read())
{
valuesList.Add(Convert.ToString(reader["CLIENTNO"]));
valuesList.Add(Convert.ToString(reader["ACCOUNT_Purpose"]));
}
Moreover, since you are converting all the columns to string; I would suggest to use a strongly typed collection like List<string> rather then ArrayList valuesList = new ArrayList();
The other answers are good, However some concerns
Lets stop using ArrayList, and use a List<T> instead
Lets use a using statement where you can
Note : I have used a ValueTuple to return more than 1 field
Example
public static List<(string clientNo, string account)> DbQueryToArray()
{
const string SqlCString = "connString";
var valuesList = new List<(string clientNo, string account)>();
using (var connection = new SqlConnection(SqlCString))
{
connection.Open();
using (var command = new SqlCommand("Select CLIENTNO, ACCOUNT_Purpose from audit.ACCOUNTS_AUDIT", connection))
{
var reader = command.ExecuteReader();
while (reader.Read())
valuesList.Add(((string)reader[0],(string)reader[1]) );
}
}
return valuesList;
}
Usage
var results = DbQueryToArray();
Assert.IsTrue(results.Any(x => x.clientNo == someValue || x.account == someValue));
best practice is to check first if the reader has rows
reader.HasRows
then close the reader and the connection
your code should look like this:
public static ArrayList DbQueryToArry()
{
string SqlCString = "connString";
SqlConnection connection = null;
ArrayList valuesList = new ArrayList();
connection = new SqlConnection(SqlCString);
using (connection)
{
connection.Open();
SqlCommand command = new SqlCommand("Select CLIENTNO, ACCOUNT_Purpose from audit.ACCOUNTS_AUDIT", connection);
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
valuesList.Add(Convert.ToString(reader[0]));
valuesList.Add(Convert.ToString(reader[1])); // add to valuelist
}
}
reader.Close(); // close reader
} //dispose connection
return valuesList;
}
Use DataTable and SqlDataAdapter to get query result in form of table. Something like this:
string connString = #"your connection string here";
string query = "select * from table";
DataTable dataTable = new DataTable();
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(query, conn);
conn.Open();
// create data adapter
SqlDataAdapter da = new SqlDataAdapter(cmd);
// this will query your database and return the result to your datatable
da.Fill(dataTable);
conn.Close();
da.Dispose();
Then you can use dataTable object to see if particular values exist.
I want my method getobject to return the result which can be looked upon by addressing the index number of the result. I thought of using an array, but then I switched to list. Which is the best method for this type of problem? How do I return the value to getobject method because I'm getting cannot convert type error.
private String[] getobject(string source, sqlconnection conn)
{
sqlcommand command = new sqlcommand("select*from ABC");
sqlreader reader = command.ExecuteReader();
List<string> dbname = new List<string>();
while(reader.read())
{
dbname = reader.getString(1);
}
return dbname;
}
Using a List<string> to build up your list is a good choice. If you want to return an array you can use the ToArray method.
private string[] getobject(string source, SqlConnection conn)
{
var command = new SqlCommand("select * from ABC");
var reader = command.ExecuteReader();
var output = new List<string>();
while(reader.Read())
{
output.Add(reader.GetString(1));
}
return output.ToArray();
}
This will convert the List<string> to a string[].
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;
}