Sqldataapter advice - c#

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. :)

Related

How to load the datagridview using OOP C#

I am a beginner at C# and .NET oop concepts. I want to load the datagridview. I don't know how to pass the data. What I tried so far I attached below.
I created a class std
public void get()
{
SqlConnection con = new SqlConnection("server =.; initial catalog=testdb; User ID=sa; Password=123");
string sql = "select * from std";
con.Open();
SqlCommand cm = new SqlCommand(sql, con);
SqlDataReader dr = cm.ExecuteReader();
while ( dr.Read())
{
string stname = dr["st_name"].ToString();
string nicnum = dr["nic"].ToString();
}
con.Close();
}
Form: I am getting data like this way
std ss = new std();
ss.get();
dataGridView1.Rows.Clear();
If I wrote like this way how to pass data into the datagridview columns? I am stuck in this area
It's easier like this:
public void FillGrid()
{
var dt = new DataTable();
var da = new SqlDataAdapter("select * from std", "server =.; initial catalog=testdb; User ID=sa; Password=123");
da.Fill(dt);
dataGridView1.DataSource = dt;
}
but if you're going to use such a low level method of database access you should consider adding a DataSet type of file to your project; visual studio will write all this code and more for you with a few mouse clicks, and it makes a good job of creating tables and adapters that are a lot easier to work with
you have made multiple mistakes. First you read data wirh dataraeader and in every iteration define two stname and nimnum variables like. So when loop ends variables are destroyed. You have to define data table and read data by dataraeader and and add them to it row by row. Or read by sqldataadapter and read it immediately and pass to datatable object.Finnaly you pass datatable as return object of function. Use this vala as datasource of datagridview property if I'm not wrong.

C# - DataTable Out of Memory exception in application to catch SQL Server "INSERT" events

I have been tasked with creating an application that monitors any "INSERT" events on a specific table. I was going to go about this using SqlDependency to create a notification link between the DB and the C# app, but it turns out I am not able to do this due to security issues.
Due to this, I have modeled my application as follows:
This is well and good, but as it turns out, the SQL table I am querying has a rather large size. The table has nearly 3.5 Million rows 55 columns. When loading into the C# DataTable object, I am getting an out of memory exception.
internal static DataTable ExecuteQuery(string query, Dictionary<string,string> parameters = null)
{
try
{
using (SqlConnection dbconn = new SqlConnection(SQLServer.Settings.ConnectionString))
using (SqlCommand cmd = new SqlCommand())
{
dbconn.Open(); // Open the connection
cmd.CommandText = query; // Set the query text
cmd.Connection = dbconn;
if (parameters != null)
{
foreach (var parameter in parameters) // Add filter parameters
cmd.Parameters.AddWithValue(parameter.Key, parameter.Value);
}
var dt = new DataTable();
using (SqlDataAdapter adpt = new SqlDataAdapter(cmd)){adpt.Fill(dt);} // MY ERROR OCCURS HERE!
dbconn.Close();
queryError = false;
return dt;
}
}
catch(Exception ex)
{
queryError = true;
EventLogger.WriteToLog("ExecuteQuery()", "Application", "Error: An error has occured while performing a database query.\r\nException: " + ex.Message);
return null;
}
}
When running the code above, I get the following error at the line for SqlDataAdapter.Fill(dt)
Exception of type 'System.OutOfMemoryException' was thrown.
Is there a way that I can either restructure my application OR prevent this incredibly high memory consumption from the DataTable class? SQL server seems capable enough to do a select * from the table but when I fill a DataTable with the same data, I use up over 6GB of RAM! Why is there so much overhead when using DataTable?
Here is a link to my flowchart.
I was able to resolve this issue by making use of the SqlDataReaderclass. This class lets you "stream" the sql result set row by row rather bringing back the entire result set all at once and loading that into memory.
So now in step 5 from the flow chart, I can query for only the very first row. Then in step 6, I can query again at a later date and iterate through the new result set one row at a time until I find the original row I started at. All the while, I am filling a DataTable with the new results. This accomplishes two things.
I don't need to load all the data from the query all at once into local memory.
I can immediately get the "inverse" DataSet. AKA... I can get the newly inserted rows that didn't exist the first time I checked.
Which is exactly what I was after. Here is just a portion of the code:
private static SqlDataReader reader;
private static SqlConnection dbconn = new SqlConnection(SQLServer.Settings.ConnectionString);
private void GetNextRows(int numRows)
{
if (dbconn.State != ConnectionState.Open)
OpenConnection();
// Iterate columns one by one for the specified limit.
int rowCnt = 0;
while (rowCnt < numRows)
{
while (reader.Read())
{
object[] row = new object[reader.FieldCount];
reader.GetValues(row);
resultsTable.LoadDataRow(row, LoadOption.PreserveChanges);
rowCnt++;
sessionRowPosition++;
break;
}
}
}
The whole class would be too large for me to post here but one of the caveats was that the interval between checks for me was long, on the order of days, so I needed to close the connection between checks. When closing the connection with a SqlDataReader, you loose your row position so I needed to add a counter to keep track of that.
Check you query for select. You probably get from database many rows.

Using DataTable.Load() method is not working in case two resultsets returned by DataReader

With the motive of enhancing the performance I am trying to eliminate Dataset use & implement DataReader. Here my Oracle Procedure returning two refcursors & when I am loading the first recordset in to the first DataTable, the next one never gets loaded.
Sample code looks something like this :
DataSet ds = new DataSet();
using (OracleConnection db = new OracleConnection(conString))
{
try
{
using (OracleCommand mycom = new OracleCommand())
{
mycom.CommandText = "myPkg.pr_mySP";
mycom.Connection = db;
mycom.CommandType = CommandType.StoredProcedure;
mycom.Parameters.Add("ref_list1", OracleDbType.RefCursor).Direction = ParameterDirection.Output;
mycom.Parameters.Add("ref_list2", OracleDbType.RefCursor).Direction = ParameterDirection.Output;
//mycom.FetchSize = mycom.FetchSize * 64;
db.Open();
using (OracleDataReader reader = mycom.ExecuteReader())
{
DataTable custMapList = new DataTable("dtcustMapList");
custMapList.Load(reader);
reader.NextResult(); // POST THIS THE SECOND DATATABLE DOESNOT GETTING POPULATED
DataTable custMapSubList = new DataTable("dtcustMapSubList");
custMapSubList.Load(reader);
ds.Tables.Add(custMapList);
ds.Tables.Add(custMapSubList);
}
}
}
catch (Exception ex)
{
returnString += "Error, " + ex.Message;
}
I know there are alternative methods like looping using while(reader.Read()) ... & then using reader.NextResult() will work, but in that case I have to change many other codes which I think can be avoided if the above works fine.
Appreciate an early response.
Looking at the reference source for the DataTable.Load method it is clear that the method calls NextResult() before exiting, so you don't need to do it.
....
if(!reader.IsClosed && !reader.NextResult())
reader.Close();
....
And by the way, there is no need to go to the source. Also MSDN says:
The Load method consumes the first result set from the loaded
IDataReader, and after successful completion, sets the reader's
position to the next result set, if any.
So you just need to remove this line
// reader.NextResult(); // POST THIS THE SECOND DATATABLE DOESNOT GETTING POPULATED

DataTable empty after .load(SqlDataReader)

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..");

How Can I Show A Search Result In A Textbox?

I have created a table code and would like to search and retrieve an answer introducing device IMEI in TextBox IMEI und when I click on the search, I want to display the result code_mck in the textbox code i want display the result:
id Imei code_mck
1 356885021519453 830782136
2 356885021519156 948790617
3 356885021518893 715398945
4 356885021518935 567456626
5 359654022104377 557960750
Initially I have a typical three-layer architecture and the search method is in the Data Layer. I have some trouble with my SQL Query:
public DataSet recherche(string code)
{
DataSet ds = null;
using (OleDbConnection cnn = new OleDbConnection(strConn))
{
cnn.Open();
string Oledb = "SELECT * FROM Code WHERE Imei=#IMEI";
using (OleDbDataAdapter adapter = new OleDbDataAdapter(Oledb, cnn))
{
adapter.SelectCommand.Parameters.AddWithValue("#IMEI", code);
ds = new DataSet();
adapter.Fill(ds, "Code");
}
}
return ds;
}
Business Logic layer:
namespace unlock2_buisness
{
public class code_imei
public DataSet rechercheduCode(string imei)
{
unlockDAL objetDataLayer = new unlockDAL();
if (imei == "")
throw new Exception("merci d'indique l'imei de recherche");
DataSet dt = null;
dt = objetDataLayer.recherche(imei);
return dt;
}
In my User Layer, the TextBox dedicated for search to display the result in textbox code is not responding, and am not getting the appropriate code by providing the device IMEI as it should be from the table.
private void btnrechercheimei_Click(object sender, EventArgs e)
{
imeiLogic.rechercheduCode(txtimei.Text);
imeiLogic.rechercheduCode(txtcode.Text);
}
I will appreciate your support.
The problem is how you use your BusinesLogic class.
public DataSet rechercheduCode(string imei) takes a string as input parameter and returns a DataSet.
When you call the method like this:
imeiLogic.rechercheduCode(txtimei.Text);
you do provide the input parameter (the value that is in textbox) but you don't store the returned Dataset in a variable.
The dataset wil have a table called Code that will hold the result rows from the query or 0 rows if nothing is found.
Staying as close as possible to your current implementation I suggest this:
private void btnrechercheimei_Click(object sender, EventArgs e)
{
// call the BLL to get a dataset
var dataSet = imeiLogic.rechercheduCode(txtimei.Text);
// get our table in the dataset
var codeTable = dataSet.Tables["Code"]; // table
// check if there was a row returned
if (codeTable.Rows.Count > 0)
{
var row = codeTable.Rows[0]; // pick the first one
txtcode.Text = row["code_mck"].ToString(); // update our textbox
}
// Add handling for 0 rows and/or more than 1 rows returned
}

Categories