Adding SQL Statement with all tables and column names into a Dictionary - c#

I need to save a sql SELECT Statement, which includes all tables and its columns in a database. The statement works fine and i can get all the names from the tables and columns i need.
The result looks as follows: (this is just psuedo-something)
table_Name Column_name
- CallerIP DT
- CallerIP ID
- CallerIP IP
- queueObject Action
- queueObject Attempt
- queueObject DestinationAddress
- queueObject ID
I thougt, i can save it into a Dictionary, where the tableName is a String, and the Colum_Names is a List of Strings
private Dictionary<string, List<string>> rowAndTables = new Dictionary<string, List<string>>();
this is my code, which should add all the tables and rows into the Dictionary
//Some code above, that doesnt matter here
command = new SqlCommand(sqlSelect, SqlConnector.getConnection());
command.Connection = SqlConnector.getConnection();
reader = command.ExecuteReader();
while (reader.Read()) {
if (tempTableName.Equals(reader.GetString(0)) == false) {
tempTableName = reader.GetString(0);
tempColumn = reader.GetString(1);
Console.WriteLine(tempTableName);
Console.WriteLine(tempColumn);
} else {
tempColumn = reader.GetString(1);
Console.WriteLine(tempColumn);
}
}
This doesnt do anything, besides printing all tables and columns.
The result looks as follows:
//CONSOLE...
CallerIP //Table
DT
ID
IP
queue_object //Table
Action
Attempt
DestinationAddress
ID
So the printing is fine.
Now I am struggeling with adding it into a Dictionary.
Can anyone help ?
Anything I did made no sense, and would just confuse anyone, I guess.

Well, if you want to fill the dictionary
private Dictionary<string, List<string>> rowAndTables =
new Dictionary<string, List<string>>();
you should modify your code slightly:
...
//DONE: wrap IDisposable (command) into using in order to release resources
using (var command = new SqlCommand(sqlSelect, SqlConnector.getConnection())) {
// Redundant, can be dropped
command.Connection = SqlConnector.getConnection();
using (var reader = command.ExecuteReader()) {
//TODO: check if the key and value are correct ones
string key = Convert.ToString(reader[0]);
string value = Convert.ToString(reader[1]);
// Do we have the key (and corresponding list) in the dictionary?
if (rowAndTables.TryGetValue(key, out var list))
// yes - we should add the value to the existing list
list.Add(value);
else
// no - we have to create key and list with value
rowAndTables.Add(key, new List<string>() {value});
}
}

Related

Alter table, passing dataype by parameter, results in a syntax error

Im using Visual Studio to create a program. In this program i have to look up for all the tables created and see if a column from a list exists, if not create it. To do that i created this variables:
Dictionary<string, List<Dictionary<string, string>>> TABLE_DICT //the string saves the name of the table, the list the columns and types
List<Dictionary<string, string>> TABLE_LIST = new List<Dictionary<string, string>>(); //list of columns in a table with its type
Dictionary<string, string> DICT = new Dictionary<string, string>(); // name of column and the type of this column
The code is the following:
try
{
conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + DBstring);
conn.Open();
foreach (KeyValuePair<string, List<Dictionary<string, string>>> TABLE_kvp in TABLE_DICT)
{
foreach (Dictionary<string, string> dic in TABLE_kvp.Value)
{
foreach (KeyValuePair<string, string> kvp in dic)
{
DataTable dt = conn.GetSchema("Columns", new string[] { null, null, TABLE_kvp.Key, kvp.Key });
if (dt.Rows.Count == 0)
{
OleDbCommand command = new OleDbCommand();
command.Connection = conn;
command.CommandText = "ALTER TABLE ? ADD COLUMN ? ? ";
command.Parameters.AddWithValue("#tablename", TABLE_kvp.Key);
command.Parameters.AddWithValue("#col", kvp.Key);
command.Parameters.AddWithValue("#val", kvp.Value);
command.ExecuteNonQuery();
command.Connection.Close();
}
}
}
}
}
catch (OleDbException ex)
{
ErrorForm ef = new ErrorForm(ex.Message, this.BackColor);
ef.ShowDialog(this);
}
The problem is that the code catch an exception for syntax error, even when i chanche the command text for the following stll does a syntax error:
command.CommandText = "ALTER TABLE ? ADD COLUMN [?] ? NULL";
command.CommandText = "ALTER TABLE ? ADD COLUMN [?] ?";
command.CommandText = "ALTER TABLE [?] ADD COLUMN ? ? ";
command.CommandText = "ALTER TABLE ? ADD COLUMN ? MEMO ";
Searching in google, at least the last one of the list, do not have to make an error,or this is what i believe, but still does. Any idea?
DDL statements can't be parametrized. You need to concatenate it in code. And because you need to do it this way, you must either
Validate the parameters, or
Be absolutely sure your parameters are trusted.
Example code with validation:
var validator = new Regex(#"^\w+$");
if (new[] { TABLE_kvp.Key, kvp.Key, kvp.Value }.All(validator.IsMatch))
{
command.CommandText = String.Format("ALTER TABLE {0} ADD COLUMN {1} {2}",
TABLE_kvp.Key,
kvp.Key,
kvp.Value);
}
Bind variables/parameters are for values only, not for table names. You have to change the table names as part of your application logic.
On top of that you cannot run DDL commands using parameters. It is only meant for DML (INSERT or UPDATE or DELETE or invoking stored procedures)

How to validate multi list

I have the following code to select the record from the database:
public List<string>[] Select(string Command)
{
string query = Command;
//Create a list to store the result
List<string>[] list = new List<string>[2];
list[0] = new List<string>();
list[1] = new List<string>();
//Open connection
if (this.OpenConnection() == true)
{
//Create Command
MySqlCommand cmd = new MySqlCommand(query, connection);
//Create a data reader and Execute the command
MySqlDataReader dataReader = cmd.ExecuteReader();
//Read the data and store them in the list
while (dataReader.Read())
{
list[0].Add(dataReader["NIK"] + "");
list[1].Add(dataReader["Password"] + "");
}
//close Data Reader
dataReader.Close();
//close Connection
this.CloseConnection();
//return list to be displayed
return list;
}
else
{
return list;
}
}
I have 2 column in my table, which is NIK and Password and the table has 2 rows which is 1,1 and 2,1.
How do I validate if the list contain NIK = 2 and Password = 1? How do I know if the select statement is successfully get the record from my table? How do I print the multi list into textbox ?
You should consider using Dictionary<string, string> instead of an array of List<string>s.
You can then print all the records:
foreach (var pair in dictionary)
Console.WriteLine(pair.Key + ", " pair.Value);
The first string in every dictionary pair is a key and the second one is a value.
how do i validate if the list contain NIK = 2 and Password = 1 ?
Go through the list and check. For example, using Enumerable.Any.
how do i know if the select statement is successfully get the record from my table ?
If no exception was thrown.
how do i print the multi list into textbox ?
Construct a string from the values returned from the database (e.g. using StringBuilder) and assign it to TextBox.Text.
BTW, you should really consider enclosing the reader and connection in using block. This way, resources will be deterministically freed even in the case of exception.
Also, consider using type-specific getters to read the data from the reader (such as GetString, GetInt32 etc.).

compare data from an array with numeric ID and insert it into a datagrid

I have a single array with random numbers as shown below
int[] numbers = new int[5] {2,5,3,7};
Also I have a table in my database with id and name in the ID have the same numerical values ​​to my array.
2 , Pedro
5 , Juan
3 , Claudio
7 , Gonzalo
I need to do is compare the numbers in the array with the id of the database, and if these are equal, showrange name associated in a datagrid
What thought is using a For loop on the array so,
for (int i = 0; i <numbers.length; i + +)
and show and thus obtain the names 'select value from table where id =' + numbers[i];
I need too much help, hope you can help me, thanks
Assuming you have valid connection you can use classes like SqlDataAdapter, DataTable and SqlConnection to fulfill a table with data you want. You also may use slightly different query to get results. Look at this code:
string numList = string.Join(",", numbers.Select(i=>i.ToString()).ToList());
// you need to have connection initialized with connection string
SqlDataAdapter a = new SqlDataAdapter("select value from table where id in (" + numList + ")", connection);
DataTable dt = new DataTable();// the result goes here
a.Fill(dt);// actually querying the database
That's it - you now have all your names from database which are corresponding to the list of IDs you have supplied. Now you can show that list in datagridview or datagrid.
So the question can be reduced to the ADO.NET part, how to retrieve the value from the id:
string sql = "SELECT value FROM dbo.table WHERE id = #id";
var pairs = new List<Tuple<int, string>>();
using (var con = new SqlConnection(yourConnectionString))
using (var cmd = new SqlCommand(sql, con))
{
con.Open();
foreach (int i in numbers)
{
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#id", i);
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
pairs.Add(Tuple.Create(i, dr.GetString(0)));
}
}
}
}
I have used a List<Tuple<int, string>> as collection to store all ID's and according names which you can use as datasource or further processing(i don't know if you only want to show the id's which have a name in your table). You can access the ID + name in this way:
foreach(var pair in pairs)
{
int id = pair.Item1;
string name = pair.Item2;
}
Note that i've used the using-statement to ensure that all unmanaged resources are getting disposed as soon as possible. That will also close the connection.
Always use parameters to prevent sql-injection or conversion issue even if you are currently not vulnerable to it.

C# List<int> populated from SQL Stored Procedure results

I'm using C# in VS 2005 (.NET 2.0) and SQL Studio 2005 on an older CMS made in the mid-'00s. I'm tasked with creating a new permission gate that allows only certain users to see certain parts of the site.
I need help populating a List list based on feedback I got when I posted this question: Populate ArrayList from Stored Procedure result set
So, now, how do get get the values from the stored procedure into a List? I realize this is a novice question but I'm a novice...
Any help is greatly appreciated.
Assuming you are getting your results from a DataReader, all you have to do is read each row to add the value to a list.
List<int> ReadList(IDataReader reader)
{
List<int> list = new List<int>();
int column = reader.GetOrdinal("MyColumn");
while (reader.Read())
{
list.Add(reader.GetInt32(column));
}
return list;
}
Remember to dispose of the DataReader when you are done with it.
You can try using the model located on this MSDN page under Using Parameters with a SqlCommand and a Stored Procedure. The example is shown here:
static void GetSalesByCategory(string connectionString, string categoryName)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create the command and set its properties.
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText = "SalesByCategory"; //Stored Procedure Name
command.CommandType = CommandType.StoredProcedure;
// Add the input parameter and set its properties.
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "#CategoryName";
parameter.SqlDbType = SqlDbType.NVarChar;
parameter.Direction = ParameterDirection.Input;
parameter.Value = categoryName;
// Add the parameter to the Parameters collection.
command.Parameters.Add(parameter);
// Open the connection and execute the reader.
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
//Instead of displaying to console this is where you would add
// the current item to your list
Console.WriteLine("{0}: {1:C}", reader[0], reader[1]);
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
}
}
it depends on how you have retreived the results
reader?
dataset?
something else?
walk through the results using
foreach (int item in object...) {
List.Add(item);
}
or possibly (I dont remember the exact DataRow syntax off the top of my head...)
foreach (datarow row in object.table[0].rows) {
List.Add(row[0]);
}
IList<int> myInts = new List<int>();
using (IDbConnection connection = new SqlConnection("yourConnectionStringGoesHere"))
{
using (IDbCommand command = new SqlCommand("spName", connection))
{
command.CommandType = CommandType.StoredProcedure;
//command.Parameters.Add(...) if you need to add any parameters to the SP.
connection.Open();
using (IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
myInts.Add(Int32.Parse(reader["someIntField"].ToString()));
}
}
}
Since you already have the table the idea would be to iterate over that table while adding the IDs of the vendor into a list.
List<VendorID_Data_Type> myList = new List<VendorID_Data_Type>();
foreach(DataRow r in GetAllVendors().Rows)
{
myList.Add(r["VendorID"]);
}
What I ended up doing is using a DataTable as an intermediary data type, which is populated by the stored procedure. Then, refactoring the DataTable as the data-source in a foreach loop, I populated the List. I needed to open a second question to get to this conclusion: 2-Column DataTable to List<int> .NET 2.0

How do I extract data from a DataTable?

I have a DataTable that is filled in from an SQL query to a local database, but I don't know how to extract data from it.
Main method (in test program):
static void Main(string[] args)
{
const string connectionString = "server=localhost\\SQLExpress;database=master;integrated Security=SSPI;";
DataTable table = new DataTable("allPrograms");
using (var conn = new SqlConnection(connectionString))
{
Console.WriteLine("connection created successfuly");
string command = "SELECT * FROM Programs";
using (var cmd = new SqlCommand(command, conn))
{
Console.WriteLine("command created successfuly");
SqlDataAdapter adapt = new SqlDataAdapter(cmd);
conn.Open();
Console.WriteLine("connection opened successfuly");
adapt.Fill(table);
conn.Close();
Console.WriteLine("connection closed successfuly");
}
}
Console.Read();
}
The command I used to create the tables in my database:
create table programs
(
progid int primary key identity(1,1),
name nvarchar(255),
description nvarchar(500),
iconFile nvarchar(255),
installScript nvarchar(255)
)
How can I extract data from the DataTable into a form meaningful to use?
The DataTable has a collection .Rows of DataRow elements.
Each DataRow corresponds to one row in your database, and contains a collection of columns.
In order to access a single value, do something like this:
foreach(DataRow row in YourDataTable.Rows)
{
string name = row["name"].ToString();
string description = row["description"].ToString();
string icoFileName = row["iconFile"].ToString();
string installScript = row["installScript"].ToString();
}
You can set the datatable as a datasource to many elements.
For eg
gridView
repeater
datalist
etc etc
If you need to extract data from each row then you can use
table.rows[rowindex][columnindex]
or
if you know the column name
table.rows[rowindex][columnname]
If you need to iterate the table then you can either use a for loop or a foreach loop like
for ( int i = 0; i < table.rows.length; i ++ )
{
string name = table.rows[i]["columnname"].ToString();
}
foreach ( DataRow dr in table.Rows )
{
string name = dr["columnname"].ToString();
}
The simplest way to extract data from a DataTable when you have multiple data types (not just strings) is to use the Field<T> extension method available in the System.Data.DataSetExtensions assembly.
var id = row.Field<int>("ID"); // extract and parse int
var name = row.Field<string>("Name"); // extract string
From MSDN, the Field<T> method:
Provides strongly-typed access to each of the column values in the
DataRow.
This means that when you specify the type it will validate and unbox the object.
For example:
// iterate over the rows of the datatable
foreach (var row in table.AsEnumerable()) // AsEnumerable() returns IEnumerable<DataRow>
{
var id = row.Field<int>("ID"); // int
var name = row.Field<string>("Name"); // string
var orderValue = row.Field<decimal>("OrderValue"); // decimal
var interestRate = row.Field<double>("InterestRate"); // double
var isActive = row.Field<bool>("Active"); // bool
var orderDate = row.Field<DateTime>("OrderDate"); // DateTime
}
It also supports nullable types:
DateTime? date = row.Field<DateTime?>("DateColumn");
This can simplify extracting data from DataTable as it removes the need to explicitly convert or parse the object into the correct types.
Please consider using some code like this:
SqlDataReader reader = command.ExecuteReader();
int numRows = 0;
DataTable dt = new DataTable();
dt.Load(reader);
numRows = dt.Rows.Count;
string attended_type = "";
for (int index = 0; index < numRows; index++)
{
attended_type = dt.Rows[indice2]["columnname"].ToString();
}
reader.Close();
Unless you have a specific reason to do raw ado.net I would have a look at using an ORM (object relational mapper) like nHibernate or LINQ to SQL. That way you can query the database and retrieve objects to work with which are strongly typed and easier to work with IMHO.
var table = Tables[0]; //get first table from Dataset
foreach (DataRow row in table.Rows)
{
foreach (var item in row.ItemArray)
{
console.Write("Value:"+item);
}
}
Please, note that Open and Close the connection is not necessary when using DataAdapter.
So I suggest please update this code and remove the open and close of the connection:
SqlDataAdapter adapt = new SqlDataAdapter(cmd);
conn.Open(); // this line of code is uncessessary
Console.WriteLine("connection opened successfuly");
adapt.Fill(table);
conn.Close(); // this line of code is uncessessary
Console.WriteLine("connection closed successfuly");
Reference Documentation
The code shown in this example does not explicitly open and close the
Connection. The Fill method implicitly opens the Connection that the
DataAdapter is using if it finds that the connection is not already
open. If Fill opened the connection, it also closes the connection
when Fill is finished. This can simplify your code when you deal with
a single operation such as a Fill or an Update. However, if you are
performing multiple operations that require an open connection, you
can improve the performance of your application by explicitly calling
the Open method of the Connection, performing the operations against
the data source, and then calling the Close method of the Connection.
You should try to keep connections to the data source open as briefly
as possible to free resources for use by other client applications.

Categories

Resources