I've got two questions basically. I have been searching quite a bit. But I mainly find console applications that are so basic I understand them regarding SQL.
However -- I take user input from my view class and send It with a method to a connect class. I want the connect class to handle all the work with SQL. Now I have a working connection and I write a correct SQL statement. How do I return it to the view class and what would you recommend like a ListBox.
When we did this in java we got a resultset and translated it so it would fit in an jtable. I wonder how I can solve this in Visual Studio.
public void askSQL (string sqlQuestion)
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = sqlQuestion;
cmd.Connection = connector;
try
{
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
MessageBox.Show("Du läser in data");
}
}
catch (Exception e)
{
MessageBox.Show("Fel vid anslutningen!" + e);
}
}
I currently have no problems with the code. The connection is working and I recieve multiple answers "Du läser in data" since there are multiple columns and rows in my table.
Have the function return DataTable object that will be populated with the database data:
public DataTable askSQL (string sqlQuestion)
{
DataTable table = new DataTable();
try
{
using (SqlDataAdapter adapter = new SqlDataAdapter(sqlQuestion, connector))
{
adapter.Fill(table);
}
}
catch (Exception e)
{
MessageBox.Show("Fel vid anslutningen!" + e);
}
return table;
}
This will return something as close to table structure as possible.. the DataTable has Rows collection, each row with data of one record from database, and each DataRow has ItemArray collection with the field values.
For exampe, to access field called "Email" from the second row, have such code:
DataTable table = connect.askSQL("Select Email From Users Where UserId In (1, 2)");
string email = table.Rows[1]["Email"].ToString();
You can iterate over the rows with simple loop:
foreach (DataRow row in table.Rows)
{
string email = row["Email"].ToString();
MessageBox.Show("Current email: " + email);
}
Hope this is enough information. :)
Related
I'm developing auction site as my University Final year project.
But I'm stuck in one problem i-e Which I click "View Details" hyperlink in Grid-view, it should compare Sno and Display its complete information present in SQL Server Table in new Tab.
Screenshot of Grid-view
string query1 = "select * from Sell ";
What condition I should apply in the above SQL Query to perform my task
If I understand you question, it sounds like you are wanting to have a link view details link clicked that retrieves the data from you sql database for the specific item being clicked.
If this is the case you are first going to want to get your sql data into a string which takes a couple more steps then what your are attempting in your example.
Instead try using a stored procedure which takes a parameter being the item your fetching and use this model:
public string StringFromDatabase()
{
SqlConnection connection = null;
try
{
var dataSet = new DataSet();
connection = new SqlConnection("Your Connection String Goes Here");
connection.Open();
var command = new SqlCommand("Your Stored Procedure Name Goes Here", connection)
{
CommandType = CommandType.StoredProcedure
};
var dataAdapter = new SqlDataAdapter { SelectCommand = command };
dataAdapter.Fill(dataSet);
return dataSet.Tables[0].Rows[0]["Item"].ToString();
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
finally
{
if (connection != null)
{
connection.Close();
}
}
}
After I run DataTable.load(SqlDataReader), the DataTable seems to be empty, but the DataReader contains results (can be seen while debugging).
Can anyone help me with this one please? I can't seem to find any solution for this problem, nor can't I find a mistake in my algorithm..
I found some solutions for using a DataAdapter & Fill(), but I'm just curious about this 'problem'.
My code:
DataTable DeviceProperties = new DataTable();
try
{
string query = "SELECT PropertyID, PropertyName from DeviceProperties WHERE DeviceID = #DeviceID;";
using (SqlCommand cmdSelectDeviceProperties = new SqlCommand(query, connectionDBTest))
{
cmdSelectDeviceProperties.Parameters.Add("#DeviceID", SqlDbType.BigInt).Value = deviceID;
using (SqlDataReader rdrSelectDeviceProperties = cmdSelectDeviceProperties.ExecuteReader())
{
if (rdrSelectDeviceProperties.HasRows)
DeviceProperties.Load(rdrSelectDeviceProperties);
else
Console.WriteLine("No Device Properties found..");
}
}
}
catch (Exception ex)
{
Console.WriteLine("Error getDeviceProperties: " + ex);
}
return DeviceProperties;
FYI: the rdrSelectDeviceProperties.HasRows passes every time, so the reader certainly contains some value.. The correct results can be found in the rdrSelectDeviceProperties, during debugging.. But the DeviceProperties data table remains empty..
EXACT PROBLEM: the data table seemed empty while debugging, because the hover over showed: '{ }'.
The rest of the code, depending on the data table, responded as the data table was empty.
SOLUTION: When you press the magnifying glass and you get the representation of the data in the data table.
My mistake was in the rest of the code (comparing the data in the data table with string, without using '.ToString()').
Learn from my mistakes..
Not sure what's causing this issue but i would use SqlDataAdapter.Fill(dataTable) instead of DataTable.Load(sqlDatareader):
DataTable tblSelectDeviceProperties = new DataTable();
using (var daSelectDeviceProperties = new SqlDataAdapter(query, connectionDBTest))
{
// no need to open/close the connection with DataAdapter.Fill
daSelectDeviceProperties.Fill(tblSelectDeviceProperties);
}
if (tblSelectDeviceProperties.Rows.Count == 0)
Console.WriteLine("No Device Properties found..");
I am creating winform application that have DataGrigView to present a table.
I have a DAL class that is responsible to work with DB.
There are one method that loads data of the table:
public static void GetItemsByOrder(int orderId, ref DataSet dataSet)
{
string queryString = #"Select Id,OrderId as [מס' הזמנה],ItemCode as[מק""ט], ItemName as [שם פריט], ReceiptDate as [ת. הספקה],
WarrantyExpDate as [באחריות עד],SuppliersItemCode as [מק""ט ספק], Supplier as [ספק], Count as[כמות], Active
FROM OrdersManager_Items where OrderId = #param";
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("#param", orderId);
SqlDataAdapter adapter = new SqlDataAdapter(command);
try
{
lock (myLock)
{
adapter.Fill(dataSet,"Items");
}
}
catch (Exception ex)
{
LogWriter.WriteLogEntry(LogWriter.LogType.ERROR, string.Format("Failed to get Items by OrderId code from DB."+
"This is due to exception: {0},\n StackTrace: {1}. ", ex.Message, ex.StackTrace));
dataSet = null;
}
}
And second method that is responsible to update the DB with the changes that were made in the table:
public static bool UpdateItemsByOrder(int orderId, DataSet data)
{
string queryString = #"Select Id,OrderId as [מס' הזמנה],ItemCode as[מק""ט], ItemName as [שם פריט], ReceiptDate as [ת. הספקה],
WarrantyExpDate as [באחריות עד],SuppliersItemCode as [מק""ט ספק], Supplier as [ספק], Count as[כמות], Active
FROM OrdersManager_Items where OrderId = #param";
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("#param", orderId);
SqlDataAdapter adapter = new SqlDataAdapter(command);
try
{
lock (myLock)
{
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
int rowsUpdated = adapter.Update(data,"Items");
return true;
}
}
catch (Exception ex)
{
LogWriter.WriteLogEntry(LogWriter.LogType.ERROR, string.Format("Failed to update Items table in DB. This is due to exception: {0},\n StackTrace: {1}. ", ex.Message, ex.StackTrace));
return false;
}
}
The problem:
If in the Items table new rows were aded or deleted - UpdateItemsByOrder add/delete the rows in the DB as expected.
But updates in existing rows of the Items table does not updated in DB.
There are no error or exceptions.
I have tryed to add builder.GetUpdateCommand() command = no result.
I will be happy to get any help or advice. Thanks
P>S> I am using this MSDN LINK to learn how to work with SQLAdapter
Ok, with the advice of sallushan I got the solution:
The reason why DataAdapter doesn't updated the DB is that updated rows in DataTable has RowState value "Unchanged" instead "Modified".
There is 2 basic ways to resolve this problem:
Update the data direcrly in DataTable and not in DGV
Call DataTable.Rows[indexOfUpdatedRowInDGV].EndEdit() method, after making updates through DGV, as described Here.
Thanks to all for a help :-)
You do realize that you run a SELECT command instead of update right?
My guess is adapter.Update just does select and then reports that no lines where updated since none were.
I am currently writing a small application to keep track of monetary ins and outs, something just to improve my general C# skills. For my Login Screen currently I have the following Code
private void Login_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'spendingInsAndOutsDataSet.Users' table. You can move, or remove it, as needed.
this.usersTableAdapter.Fill(this.spendingInsAndOutsDataSet.Users);
}
private void button1_Click(object sender, EventArgs e)
{
string userNameText = userName.Text;
string passwordText = password.Text;
foreach (DataRow row in spendingInsAndOutsDataSet.Users)
{
if (row.ItemArray[4].Equals(userNameText) && row.ItemArray[5].Equals(passwordText))
{
MessageBox.Show("Login Successful");
MainGUI newForm = new MainGUI();
this.Visible = false;
newForm.Show();
break;
}
else
{
userName.Text = String.Empty;
password.Text = String.Empty;
MessageBox.Show("Login Failed");
break;
}
}
}
What I am looking to do when the Login is Sucessful is to write the MachineName of the current PC to a field in Users table in my SQL Database. That way when I come to start creating records I can quickly find my UsersId (which is a foreign key in my Transactions table).
I know you can get the Active Machine Name using the System.Enviroments path but Im unsure exactly how to go about writing the update. I know how to do it using a SqlCommand but I am wondering if there is a simpler way using the DataRows I have used within the ForEach loop.
Thanks in advance, any questions let me know.
James
Assuming it is an Access database (If not then make the necessary changes):
Use an Adapter to fill a table with your results. Then compare the row columns with the information provided by the user. Don't forget to use parameters to avoid injections that may potentially ruin your database or expose your user's information to a hacker.
DataTable dt = new DataTable();
String sql = "SELECT * FROM users WHERE user = #user and password=#password"
OleDbConnection connection = getAccessConnection();
OleDbDataAdapter da = new OleDbDataAdapter(sql, connection);
da.SelectCommand.Parameters.Add("#user", OleDbType.VarChar).Value = userNameText;
da.SelectCommand.Parameters.Add("#password", OleDbType.VarChar).Value = password.Text;
try
{
connection.Open();
da.Fill(dt);
connection.Close();
}
catch(OleDbException ex)
{
connection.Close();
MessageBox.Show(ex.ToString());
}
if(dt.Rows.Count == 1)
return true; //username && password matches
else if(dt.Rows.Count == 0)
return false; // does not match
You could also use AddWithValue for your parameters.
da.SelectCommand.Parameters.AddWithValue("#user", userNameText);
getAccessConnection() is a predefined OleDbConnection function that has the connection to the database setup and creates a new instance of the connection for you (that I have created for myself).
public OleDbConnection getAccessConnection()
{
this.connection = new OleDbConnection();
this.connection.ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
+ Classified.SOURCE + ";Jet OLEDB:Database Password="
+ Classified.PASS + ";";
return this.connection;
}
It is preferred to create classes for all of these functions for developers who may join in on the project. Also read up on C# test driven development as well.
Also it looks like your loop will break even if that one record fails, only allowing it to go to it's first record.
Onto creating your own data set and filling it with queried tables is also useful. Here is a brief example:
DataSet ds = new DataSet();
ds.Tables.Add(dt, "userSearchedTable");
ds.Tables["userSearchedTable"].Rows[0][1].ToString();
Then you can declare a specific data table within the set when ever you need to.
In your foreach loop, set the MachineName of the current PC on relevant row then at the end of the method call:
this.usersTableAdapter.Update(this.spendingInsAndOutsDataSet.Users);
This will update the database with the machine name
However looking at your code there are a few additional comments to make I'd like to add to improve what you have:
You are loading the entire data table and then checking it for the username and password. Really you query for the user ID in the database, load that single row and check the password. If you have many users, your current implementation will create a lot of network traffic.
Instead of:
foreach (DataRow row in spendingInsAndOutsDataSet.Users)
Consider using something like:
foreach (SpendingInsAndOutsDataSet.UsersRow row in spendingInsAndOutsDataSet.Users)
i.e. the strongly typed version of the data row object. This means you can use:
row.Username.Equals(userNameText)
instead of
row.ItemArray[4].Equals(userNameText)
Also if you are anticipating that this will be used over a network, you should look to encrypt the passwords.
At present i have a the following code populating a datagridview showing the user account information on our system. What i want to do do is have a checkbox on the datagridview for the option "accountenabled" and a update button at the bottom of the form so it will update all users that have had changes made against them. I am currently pulling the data back using an sqldatareader however from what i have read i need to use a sqldataadapter. I`ve created the column names on the datagridview and the reader is currently pulling everything back correctly.
Could someone please point me in the right direction of doing this with an sqldatadapter?
Thanks
public UserAdmin()
{
InitializeComponent();
//Load user list
// Locals
Functionality func = new Functionality();
SqlConnection supportDB = null;
SqlCommand CheckUser = null;
SqlDataReader rdr;
DataSet ds = new DataSet();
DataTable dt = new DataTable();
string User = System.Environment.UserName.ToString();
string spName = "gssp_ShowAllUsers";
try
{
using (supportDB = new SqlConnection(GSCoreFunc.ConnectionDetails.getConnectionString(ConnectionType.SupportDB)))
{
using (CheckUser = new SqlCommand(spName, supportDB))
{
// Set the command type
CheckUser.CommandType = CommandType.StoredProcedure;
// Populate the parameters.
CheckUser.Parameters.Add(func.CreateParameter("#spErrorID", SqlDbType.Int, ParameterDirection.Output, DBNull.Value));
// Open the connection and populate the reader with the SP output
supportDB.Open();
rdr = CheckUser.ExecuteReader();
if (CheckUser.Parameters["#spErrorID"].Value != null)
{
throw new InvalidOperationException();
}
// If the data reader has rows display output on label
if (rdr.HasRows)
{
//Output values
while (rdr.Read())
{
//Bind to data table
dgvUsers.Rows.Add(rdr["agentID"].ToString(), rdr["createdon"].ToString(), rdr["firstname"].ToString(), rdr["lastname"].ToString(), rdr["username"].ToString(), rdr["emailaddress"].ToString(), rdr["Departments"].ToString(), rdr["accountenabled"].ToString(), rdr["AgentAccountLevel"].ToString());
}
}
// Close reader and connection.
rdr.Close();
supportDB.Close();
}
}
}
catch (Exception ex)
{
//Show error message
string error = ex.ToString(); //Real error
string FriendlyError = "There has been error loading the user list"; // Error user will see
GSCoreFunc.ShowMessageBox.msgBoxErrorShow(FriendlyError);
//Log error to ExceptionDB
GSCoreFunc.ReportException.reportEx(GSCoreFunc.ApplicationInformation.ApplicationName, error, FriendlyError, GSCoreFunc.ApplicationInformation.ComputerName, GSCoreFunc.ApplicationInformation.OperatingSystem, GSCoreFunc.ApplicationInformation.screenSize, GSCoreFunc.ApplicationInformation.IPAdddress, GSCoreFunc.ApplicationInformation.domainName);// Pass error to GSCoreFunc to log to the ExceptionDB
}
}
private void btClose_Click(object sender, EventArgs e)
{
//Close window
Close();
}
}
}
There is nothing wrong with using the SqlDataReader. The SqlDataAdapter is a higher level api that allows you to iterate through an SqlDataReader and store a copy of the results in a DataTable or a DataSet. This copy can then be used as the data source for your DataGridView.
One thing I would change with your code would be to use data binding instead of generating each row manually. If you set the DataSource property of the grid to either your SqlDataReader or to a DataTable filled by an SqlDataAdapter and then call the grids DataBind() method the grid should be filled automatically with your data.
To control the columns you would make sure your query only returns the required columns, and you would define the column setup in your aspx-file.
Using data binding is generally an easier and more flexible approach, so you should consider using that instead.
Look at this code
Initialize a sql adapter and fill with data source . Use a connection string other than using sql data source because it would be easy for customizing. :)