Ok - I have finally got my connection string and sql string correct in this WPF form. I kept getting reader exceptions until I finally got the sql string the correct way, so since I am not getting errors now - I am assuming it is correct. Have inserted a breakpoint at IDbCommand and stepped through, and all steps seem to go fine. But the program locks up and does not display any data in the datagrid. Cannot even click on the form once all statements are processed. What have I missed here?
This is a Progress OpenEdge DB - and this is the recommended connection and command from Progress.
private void MonReadButton_Click(object sender, RoutedEventArgs e)
{
var estNum = EstTextBox.Text;
{
string connectString = "DSN=****;uid=**;pwd=*****;host=****;port=****;db=****;";
using (OdbcConnection dbConn = new OdbcConnection(connectString))
{
try
{
dbConn.Open();
}
catch (Exception)
{
MessageBox.Show("connection failed");
}
IDbCommand dbcmd = dbConn.CreateCommand();
string sqlstr = #"SELECT ""Estimate"".""Labor-Cost"" FROM ""GAMS1"".""PUB"".""Estimate"" WHERE ""Estimate"".""Estimate-ID""=" + estNum;
dbcmd.CommandText = sqlstr;
IDataReader reader = dbcmd.ExecuteReader();
while (reader.Read())
{
DataTable dt = new DataTable();
dt.Load(reader);
DataGrid1.ItemsSource = dt.DefaultView;
}
reader.Close();
reader = null;
dbcmd.Dispose();
dbcmd = null;
dbConn.Close();
}
}
}
Related
I want to display data in a datagrid based on value selected in a ComboBox but my datatable function returns null and nothing is displayed in the datagrid.
public DataTable ReadData(User user)
{
using (SqlConnection db = new SqlConnection(AppConnect.Connection))
{
string query = "SELECT moduleCode,moduleName,modCredits,modHrsLeft FROM [Module] WHERE userName=#userName";
try
{
using (SqlCommand command = new SqlCommand(query, db))
{
if (db.State == ConnectionState.Closed)
{
db.Open();
command.Parameters.AddWithValue("#userName", user.UserName);
SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
table = new DataTable();
dataAdapter.Fill(table);
}
}
db.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return table;
}
}
This function is in a class library. The function is called in the WPF project, this is the code:
private void BtnDisplay_Click(object sender, RoutedEventArgs e)
{
string userName = CmboxUserN.SelectedItem.ToString();
User user1 = new User
{
UserName = userName
};
DataTable table = data.ReadData(user1);
gridModules.DataContext= table;
}
Try these changes. It seems that the line table = new DataTable(); is never being hit. You don't need to check to make sure the connection is in a closed state because you are using a using statement.
public DataTable ReadData(User user)
{
using (SqlConnection db = new SqlConnection(AppConnect.Connection))
{
string query = "SELECT moduleCode,moduleName,modCredits,modHrsLeft FROM [Module] WHERE userName=#userName";
try
{
using (SqlCommand command = new SqlCommand(query, db))
{
db.Open();
command.Parameters.AddWithValue("#userName", user.UserName);
SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
table = new DataTable();
dataAdapter.Fill(table);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return table;
}
}
Also, you don't need to .Close() the connection because the SqlConnection is in a using statement, which means the object will be disposed of when the scope of the using statement is exited.
One other tip: You should change the code to have the try catch around everyting and if there are any errors at all, log the errors to console and return a new DataTable().
I created an app in C# with SQLite Database. When I want to display data from database into a text box, I receive the error: "Input string was not in a correct format".
Here is my code:
public Form1()
{
InitializeComponent();
connectionString = #"Data Source=.\mydb.db;Version =3Integrated Security=True";
}
private void button1_Click(object sender, EventArgs e)
{
using (SQLiteConnection conn = new SQLiteConnection(connectionString))
{
try
{
conn.Open();
if(conn.State == ConnectionState.Open)
{
//MessageBox.Show("Succes!");
SQLiteDataReader reader = null;
SQLiteCommand cmd = new SQLiteCommand("select username from users where id='1'", conn);
reader = cmd.ExecuteReader();
while(reader.Read())
{
textBox1.Text = reader.GetValue(0).ToString();
}
}
conn.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
The code from Microsoft's example is like this:
while (reader.Read())
{
Console.WriteLine(String.Format("{0}", reader[0]));
}
So maybe
while(reader.Read())
{
textBox1.Text = reader[0];
}
That said I would be using the debugger to find out more about the element and what you should display.
Just putting it out there but I would be looking and c# MVC or C# Core with entity framework. It's much easier to interact with a database and something I would encourage.
Currectly I am studying and learning and I just wanted to know some logic of this database connection in C#. I wanted to know why the while loop is used I means if I don't use it, will it affect the program or will the program run fine if I take it out. I just wanted to know is it wise to use it or just take it out from the program. Can someone please help me ?? Thank you
private bool filled;
public DataSet ds = new DataSet();
private void bnt_displaylog_Click(object sender, EventArgs e)
{
try
{
string dbconnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Elevator_Database.accdb;";
string dbcommand = "Select * from Log;";
OleDbConnection conn = new OleDbConnection(dbconnection);
OleDbCommand comm = new OleDbCommand(dbcommand, conn);
OleDbDataAdapter adapter = new OleDbDataAdapter(comm);
conn.Open();
//MessageBox.Show("Connection Open ! ");
**while (filled == false)**
{
adapter.Fill(ds);
filled = true;
}
conn.Close();
}
catch (Exception)
{
MessageBox.Show("Can not open connection ! ");
string message = "Error in connection to datasource";
string caption = "Error";
MessageBoxButtons buttons = MessageBoxButtons.OK;
DialogResult result;
result = MessageBox.Show(message, caption, buttons);
}
database_listbox.Items.Clear();
foreach (DataRow row in ds.Tables[0].Rows)
{
database_listbox.Items.Add(row["Date"] + "\t\t" + row["Time"] + "\t\t" + row["Action"]);
}
}
That's just code that was written in a very unclear manner. The while loop will never loop at all. The loop body will either be executed once, or not at all, depending on the value of filled.
In other words, the code could have been written more clearly as:
conn.Open();
if( ! filled )
{
adapter.Fill(ds);
filled = true;
}
conn.Close();
But even then, the code is doing the wrong thing. Think about the case where filled is true. The code that's actually executed is:
conn.Open();
conn.Close();
and what's the point of doing that?
In any case, what the code actually does, either with while or if, is call adapter.Fill(ds) only the first time through. Given that, we should skip setting up the connection entirely when we don't make that call. And let's refactor the code to make it a bit more clear:
private bool filled = false;
public DataSet ds = new DataSet();
private void bnt_displaylog_Click(object sender, EventArgs e)
{
loadDisplayLog();
database_listbox.Items.Clear();
foreach (DataRow row in ds.Tables[0].Rows)
{
database_listbox.Items.Add(
row["Date"] + "\t\t" + row["Time"] + "\t\t" + row["Action"]
);
}
}
private void loadDisplayLog(object sender, EventArgs e)
{
if( filled ) return;
try
{
string dbconnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Elevator_Database.accdb;";
string dbcommand = "Select * from Log;";
OleDbConnection conn = new OleDbConnection(dbconnection);
OleDbCommand comm = new OleDbCommand(dbcommand, conn);
OleDbDataAdapter adapter = new OleDbDataAdapter(comm);
conn.Open();
adapter.Fill(ds);
conn.Close();
filled = true;
}
catch (Exception)
{
MessageBox.Show("Can not open connection ! ");
string message = "Error in connection to datasource";
string caption = "Error";
MessageBoxButtons buttons = MessageBoxButtons.OK;
DialogResult result;
result = MessageBox.Show(message, caption, buttons);
}
}
There are still some issues with the exception handling in this code - will the connection be closed if adapter.Fill(ds); throws an exception? Oops. But I'll leave the rest as an exercise for the reader...
Im trying to build up a little status-tool. I need to get results of multiple queries (about 4-5). The general connection-setup and 'how-to-read-data' is already done but I cant figure out how the another query executed.
Everything I found while searching for it is for the SqlClient. Im totally overcharged with this.
Here is my code so far (be patient, im a newbie to this):
private void button1_Click(object sender, EventArgs e)
{
if(listView1.Items.Count > 1)
{
listView1.Items.Clear();
}
var listMember = new List<string>{};
var listOnline = new List<string>{};
// SQL PART //
string connString = "Server=10*****;Port=3306;Database=e***;Uid=e***;password=********************;";
MySqlConnection conn = new MySqlConnection(connString);
MySqlCommand command = conn.CreateCommand();
command.CommandText = "SELECT fullname,online FROM member WHERE active = '1' ORDER BY online DESC";
try
{
conn.Open();
}
catch (Exception ex)
{
listView1.Items.Add("Error: " + ex);
}
MySqlDataReader reader = command.ExecuteReader();
while(reader.Read())
{
listMember.Add(reader["fullname"].ToString());
listOnline.Add(reader["online"].ToString());
}
conn.Close();
// SQL ENDING //
// SET ENTRIES TO LISTVIEW //
int counter = 0;
foreach(string member in listMember)
{
ListViewItem item = new ListViewItem(new[] { member, listOnline.ElementAt(counter) });
item.ForeColor = Color.Green;
listView1.Items.Add(item);
counter++;
}
}
Im not really sure how the design/layout will look like in the end, so I would like to just append the results to lists in the sql-part to process the data later out of the lists.
Do I really have to setup a complete new connection after conn.Close()? Or is there any other way? I can just imagine: 5 queries with their own connection,try,catch and 2 loops... this will get about 100-200 lines just for getting the results out of 5 queries. Isnt that a bit too much for such an easy thing?
Hope for some help.
Greetings.
According to the new comments my latest code:
Top:
public partial class Form1 : Form
{
public static string connString = "Server=10****;Port=3306;Database=e****;Uid=e****;password=****;";
public Form1()
{
InitializeComponent();
MySqlConnection conn = new MySqlConnection(connString); // Error gone!
}
Body part:
public void QueryTwoFields(string s, List<string> S1, List<string> S2)
{
try
{
MySqlCommand cmd = conn.CreateCommand(); // ERROR: conn does not exist in the current context.
cmd.CommandType = CommandType.Text;
string command = s;
cmd.CommandText = command;
MySqlDataReader sqlreader = cmd.ExecuteReader();
while (sqlreader.Read())
{
S1.Add(sqlreader[0].ToString());
S2.Add(sqlreader[1].ToString());
}
sqlreader.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
if(listView1.Items.Count > 1)
{
listView1.Items.Clear();
}
var listMember = new List<string>{};
var listOnline = new List<string>{};
using (conn) // ERROR: conn does not exist in the current context.
{
conn.Open();
///...1st Query
QueryTwoFields("SELECT fullname,online FROM member WHERE active = '1' ORDER BY online DESC",listMember,listOnline);
//...2nd query
//QueryTwoFields("your new Select Statement", otherList, otherList);
}
}
You don't have to close connection every time you execute one query rarher than close the sqlreader assigned to that connection. Finally when all of your queries have been executed you close the connection. Consider also the use of using:
You cal also define a method for execution your Query in order for your code not to be repetive:
public void QueryTwoFields(string s, List<string> S1, List<string> S2)
///Select into List S1 and List S2 from Database (2 fields)
{
try
{
MySqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
string command = s;
cmd.CommandText = command;
MySqlDataReader sqlreader = cmd.ExecuteReader();
while (sqlreader.Read())
{
S1.Add(sqlreader[0].ToString());
S2.Add(sqlreader[1].ToString());
}
sqlreader.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
if(listView1.Items.Count > 1)
{
listView1.Items.Clear();
}
var listMember = new List<string>{};
var listOnline = new List<string>{};
// SQL PART //
using (conn)
{
conn.Open();
///...1st Query
QueryTwoFields("SELECT fullname,online FROM member WHERE active = '1' ORDER BY online DESC",listmember,listonline)
//...2nd query
QueryTwoFields("your new Select Statement",myOtherList1,myOtherlist2)
....
}
}
EDIT :
Take in mind you cant define QueryTwoFields method inside button handler. You must define it outside (see code above).
Also Define your connection data in the start of the programm:
namespace MyProject
{
/// <summary>
/// Defiine your connectionstring and connection
/// </summary>
///
public partial class Form1 : Form
{ public static string connString = "Server=10*****;Port=3306;Database=e***;Uid=e***;password=********************;";
MySqlConnection conn = new MySqlConnection(connString);
.........
Datatables are fantastic
Using a data table is a nice way to do both read and write. And it comes with the luxury of eveything you can do with a datatable - like asssigning it directly to a datagrid control, sorting, selecting and deleting while disconnected.
The sample below assumes a MySqlConnection conection property managed by calls to your own OpenConnection() and CloseConnection() methods not shown.
Simple datatable read demo:
public DataTable Select(string query = "")
{
//Typical sql: "SELECT * FROM motorparameter"
DataTable dt = new DataTable();
//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();
dt.Load(dataReader);
//close Data Reader
dataReader.Close();
//close Connection
this.CloseConnection();
//return data table
return dt;
}
else
{
return dt;
}
}
In case of writing back the datatable to the database - supply the SQL you used in the read (or would have used to read to the data table):
public void Save(DataTable dt, string DataTableSqlSelect)
{
//Typically "SELECT * FROM motorparameter"
string query = DataTableSqlSelect;
//Open connection
if (this.OpenConnection() == true)
{
//Create Command
MySqlCommand mySqlCmd = new MySqlCommand(query, connection);
MySqlDataAdapter adapter = new MySqlDataAdapter(mySqlCmd);
MySqlCommandBuilder myCB = new MySqlCommandBuilder(adapter);
adapter.UpdateCommand = myCB.GetUpdateCommand();
adapter.Update(dt);
//close Connection
this.CloseConnection();
}
else
{
}
}
The neat thing the datatable is extremely flexible. You can run your own selects against the table once it contains data and before writing back you can set or reset what rows needs updating and by default the datatable keeps track of what rows you update in the table. Do not forget primary key column(s) for all tables in the db.
For multiple queries consider if possible using a join between the database tables or same table if data related or use a UNION sql syntax if column count and type of data is the same. You can allways "create" your extra column in the select to differ what data comes from what part of the UNION.
Also consider using CASE WHEN sql syntax to conditionally select data from different sources.
private void button1_Click(object sender, EventArgs e)
{
try
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Data Source=*******;Initial Catalog=ChatApp;User ID=Chatapplication;Password=****";
conn.Open();
SqlCommand cmd = new SqlCommand();
string chatroomidno = textBox1.Text;
string chatroomname = textBox2.Text;
//cmd.CommandText = "Select ChatRoomID=#ChatRoomID,ChatRoomName=#ChatRoomName from tblChatRoom";
//cmd.Connection = conn;
SqlDataAdapter adapt = new SqlDataAdapter("Chatroomapp",conn);
adapt.SelectCommand.CommandType = CommandType.StoredProcedure;
DataSet ds=new DataSet();
DataTable dt = new DataTable();
adapt.SelectCommand.Parameters.Add(new SqlParameter("#ChatRoomID", SqlDbType.VarChar, 100));
adapt.SelectCommand.Parameters["#ChatRoomID"].Value = chatroomidno;
adapt.SelectCommand.Parameters.Add(new SqlParameter("#ChatRoomName", SqlDbType.VarChar, 50));
adapt.SelectCommand.Parameters["#ChatRoomName"].Value = chatroomname;
adapt.Fill(ds, "tblChatRoom");
if (dt.Rows.Count > 0)
{
MessageBox.Show("Connection Succedded");
}
else
{
MessageBox.Show("Connection Fails");
}
}
catch (Exception ex)
{
MessageBox.Show("Error", ex.Message);
}
}
While compiling the program I got only connection fails message box, in the database. I found correct, how to overcome the program to get the connection succeeded message box.
Well, you're filling the ds data set - but then you're checking the dt data table for presence of rows... that's never going to work, of course!
If you only need a single DataTable - just use and fill that data table alone - no need for the overhead of a DataSet. Also, put your SqlConnection and SqlCommand into using blocks like this:
using (SqlConnection conn = new SqlConnection("Data Source=*******;Initial Catalog=ChatApp;User ID=Chatapplication;Password=****"))
using (SqlCommand cmd = new SqlCommand("Chatroomapp", conn))
{
string chatroomidno = textBox1.Text;
string chatroomname = textBox2.Text;
SqlDataAdapter adapt = new SqlDataAdapter(cmd);
adapt.SelectCommand.CommandType = CommandType.StoredProcedure;
adapt.SelectCommand.Parameters.Add(new SqlParameter("#ChatRoomID", SqlDbType.VarChar, 100));
adapt.SelectCommand.Parameters["#ChatRoomID"].Value = chatroomidno;
adapt.SelectCommand.Parameters.Add(new SqlParameter("#ChatRoomName", SqlDbType.VarChar, 50));
adapt.SelectCommand.Parameters["#ChatRoomName"].Value = chatroomname;
// fill the data table - no need to explicitly call `conn.Open()` -
// the SqlDataAdapter automatically does this (and closes the connection, too)
DataTable dt = new DataTable();
adapt.Fill(dt);
if (dt.Rows.Count > 0)
{
MessageBox.Show("Connection Succedded");
}
else
{
MessageBox.Show("Connection Fails");
}
}
And just because you get back no rows in dt.Rows doesn't necessarily mean that your connection failed..... it could just be that there are no rows that match your search critieria! The connection worked just fine - but the SQL command just didn't return any rows.
Connection failed means that something went wrong between your program and the database. No records returned does not mean that the connection failed. It just means that your table is empty - it contains no records.
Using ADO.NET and a stored procedures would have been a little different from what you have done it. If you need to check if the connection failed, maybe it is better to check the type of exception that is returned in the catch part.
Below is how I would have done it. I would have created a separate method that would have handled my call, and then in your button1_Click I would have just called this method:
public async Task<ChatRoom> GetAsync(string chatRoomId, string chatRoomName)
{
try
{
string connectionString = ConfigurationManager.ConnectionStrings["Db"].ConnectionString;
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
await sqlConnection.OpenAsync();
using (SqlCommand sqlCommand = new SqlCommand("ChatRooms_Get", sqlConnection))
{
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.Add(new SqlParameter("#ChatRoomID", chatRoomId));
sqlCommand.Parameters.Add(new SqlParameter("#ChatRoomName", chatRoomName));
using (SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync())
{
ChatRoom chatRoom = null;
if (await sqlDataReader.ReadAsync())
{
chatRoom = new ChatRoom();
chatRoom.Id = sqlDataReader.GetFieldValue<string>(0);
chatRoom.Name = sqlDataReader.GetFieldValue<string>(1);
chatRooms.Add(chatRoom);
}
return chatRoom;
}
}
}
}
catch (Exception exception)
{
// Try checking if the connection failed here
throw exception;
}
}
My chat room domain model could have looked like this:
public class ChatRoom
{
public string Id { get; set; }
public string Name { get; set; }
}
And the stored procedure would have looked like this:
CREATE PROCEDURE [dbo].[ChatRooms_Get]
(
#ChatRoomID VARCHAR(100),
#ChatRoomName VARCHAR(50)
)
AS
BEGIN
SET NOCOUNT ON;
SELECT
ChatRoomID,
ChatRoomName
FROM
tblChatRoom
WHERE
ChatRoomID = #ChatRoomID
AND ChatRoomName = #ChatRoomName;
END
GO
And then in the calling method you would get the chatroom and do with it whatever you need to do with it. For this example I just checked if it exists or not:
try
{
ChatRoom chatRoom = await chatRoomRepository.GetAsync(chatRoomId, chatRoomName);
if (chatRoom != null)
{
MessageBox.Show("Record found");
}
else
{
MessageBox.Show("No record found");
}
}
catch (Exception exception)
{
throw exception;
}
I hope this can help.