I'm having a problem with data set. I'm using one to populate text boxes of my form. The user selects a value to search from, they press a button and then the text boxes are populated. This works fine for the first record but I want to page through them. I've declared a data set to be used by my other methods but when it gets to paging the returned rows I keep getting an Object reference error. Can anyone shed some light on where I'm going wrong?
Declaring Variables:
//creates a global dataset for the copies table
DataSet dataSetHM;
//create default row values
int MaxRows = 0;
int inc = 0;
The connection to the database and filling the data set:
protected void ExecuteSelectCopies(string sName)
{
SqlConnection connection = new SqlConnection(GetConnectionString());
string sql =
"SELECT tblCopies.CopyID, tblSoftware.SoftwareName, tblCopies.AssetName, tblCopies.Location,"
+ " tblCopies.LicenceKey, tblCopies.OEM, tblCopies.State, tblCopies.InstallationDate"
+ " FROM tblCopies"
+ " INNER JOIN tblSoftware ON tblCopies.SoftwareID = tblSoftware.SoftwareID"
+ " WHERE tblSoftware.SoftwareName = #SoftwareName"
+ " ORDER BY tblCopies.CopyID";
SqlDataAdapter adapterHM = new SqlDataAdapter();
SqlCommand select = new SqlCommand(sql, connectionHM);
adapter.SelectCommand = select;
select.Parameters.Add(new SqlParameter("#SoftwareName", sName));
//open the connection
connectionHM.Open();
dataSetHM = new DataSet();
adapterHM.Fill(dataSetHM, "Copies");
NavigateCopies();
MaxRows = dataSetHM.Tables["Copies"].Rows.Count;
connectionHM.Close();
}
The method for filling the text boxes:
private void NavigateCopies()
{
DataRow dRow = dataSetHM.Tables["Copies"].Rows[inc];
TextBoxCopyID.Text = dRow.ItemArray.GetValue(0).ToString();
TextBoxSoftwareName.Text = dRow.ItemArray.GetValue(1).ToString();
DropDownListAssetName.SelectedItem.Text = dRow.ItemArray.GetValue(2).ToString();
DropDownListLocation.SelectedItem.Text = dRow.ItemArray.GetValue(3).ToString();
TextBoxLicence.Text = dRow.ItemArray.GetValue(4).ToString();
DropDownListType.SelectedItem.Text = dRow.ItemArray.GetValue(5).ToString();
DropDownListState.SelectedItem.Text = dRow.ItemArray.GetValue(6).ToString();
TextBoxInstall.Text = dRow.ItemArray.GetValue(7).ToString();
}
And finally the button for the next record:
protected void ButtonNext_Click(object sender, EventArgs e)
{
if (inc != MaxRows - 1)
{
inc++;
NavigateCopies();
}
else
{
MessageBox.show("No more Rows");
}
}
Any help with this would be very much appreciated. I honestly can't understand why the data set works for the navigation method initially but not for the second. I've been using this http://www.homeandlearn.co.uk/csharp/csharp_s12p7.html as a guide, their example displays data on page load where as mine is displayed when a search parameter is selected. I don't know if this is a problem but a bit more information never hurts!
Persist the DataSet in the Session/Cache/ViewState (which ever one of these is the most applicable solution for you).
That way you can retrieve the DataSet between postback's and continue to display the data that is required.
Here is how to accomplish this (albeit a simple example) and an article that delves into object persistence within asp.net: asp.net object persistence.
Related
Iam currently working on a book management project and I'm using SQL Server from Visual Studio. I have a Book Category table in the database and I'm trying to place it in a combobox.
This the code - I don't see anything wrong with it but the categories are taking so long to be visible in the combobox.
Also the list is repetitive, is it maybe because of the while Loop? If so is there any way to fix it?
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
con.ConnectionString = (#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\malek\source\repos\BookStore\BookStore\BOOKDB.mdf;Integrated Security=True");
scmd.Connection = con;
con.Open();
scmd.CommandText = "SELECT CATEGORY FROM BOOKCAT";
var rd = scmd.ExecuteReader();
while (rd.Read())
{
List.Add(Convert.ToString(rd[0]));
}
int i = 0;
while (i < List.LongCount())
{
comboBox1.Items.Add(List[i]);
i = i + 1;
}
}
catch (Exception EX)
{
MessageBox.Show(EX.Message);
}
finally
{
con.Close();
}
}
What did I miss?
NOTE: I am not getting any errors!!
How do you mean with data binding?
Like this
var da = new SqlDataAdapter(
"SELECT DISTINCT CATEGORY FROM BOOKCAT ORDER BY CATEGORY"
#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\malek\source\repos\BookStore\BookStore\BOOKDB.mdf;Integrated Security=True"
);
var dt = new DataTable();
da.Fill(dt);
categoryComboBox.DisplayMember = "CATEGORY";
categoryComboBox.ValueMember = "CATEGORY";
categoryComboBox.DataSource = dt;
And when you want the thing the user selected:
var cat = categoryComboBox.SelectedValue as string;
Simple eh?
It gets even easier if you use a strongly typed dataset; for that you just add a new DataSet type file to your project (must use net framework not net core/5+), drag your db into your dataset, add a query to the category TableAdapter that gets the distinct categories (like above) then open the data sources window, change Category to a combo and tag it onto the form. No code to write; vs will write it all
Based on the code you've posted, it looks like you're loading the categories from the database in the SelectedIndexChanged event of comboBox1.
So, every time you choose a new item from comboBox1 you're executing this code; you're going to the database and loading everything from the BOOKCAT table and you're putting those items into List and comboBox1. That is why you're seeing duplicated categories. It's probably also why it takes so long for a category to be visible in the ComboBox.
You probably don't want to load the ComboBox items from the database every time the selected index changes, so you should do that somewhere else. For example, you could do it in the Form's constructor, or in the 'Load' event.
I posted this not long ago, but no I have to update the question to ensure I get the right answer.
I have a GridView. I need to update an SQL table based on values from the GridView.
When a user clicks the default EDIT button on the GridView, changes whatever they change, then hits UPDATE. Here is where I run into problems. I've tried multiple OnRowEditing, OnRowUpdating, OnRowUpdate as the button control.
Here is the code I use to that.
protected void gvReviewedPolicy_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
DateTime dateTime = DateTime.Now;
//GridViewRow editRow = gvReviewedPolicy.Rows[gvReviewedPolicy.EditIndex];
//string Emailed = editRow.Cells[7].Text;
//string UniqClient = editRow.Cells[1].Text;
//string UniqPolicy = editRow.Cells[3].Text;
string UniqClient = gvReviewedPolicy.SelectedRow.Cells[2].Text;
string UniqPolicy = gvReviewedPolicy.SelectedRow.Cells[3].Text;
//string Email = Emailed.ToString();
//string dt = dateTime.ToString();
//string Up = UniqClient.ToString();
MessageBox.Show(UniqClient);
MessageBox.Show(UniqPolicy);
//MessageBox.Show(dt);
string query = "UPDATE [Reviewed_Renewal_Policy] SET [DateUpdated] = #dateTime where ([UniqClient] = #UniqClient) AND ([UniqPolicy] = #UniqPolicy)";
using (SqlConnection conn = new SqlConnection("Data Source=GTU-BDE01;Initial Catalog=TestDB;Integrated Security=True"))
{
using (SqlCommand comm = new SqlCommand(query, conn))
{
comm.Parameters.AddWithValue("#UniqClient", UniqClient);
comm.Parameters.AddWithValue("#UniqPolicy", UniqPolicy);
//comm.Parameters.AddWithValue("#Emailed", Emailed);
comm.Parameters.AddWithValue("#dateTime", dateTime);
conn.Open();
comm.ExecuteNonQuery();
conn.Close();
}
}
}
I have some commented out because I was trying different things. However, the code that says
GridViewRow editRow = gvReviewedPolicy.Rows[gvReviewedPolicy.EditIndex];
string Emailed = editRow.Cells[7].Text;
string UniqClient = editRow.Cells[1].Text;
string UniqPolicy = editRow.Cells[3].Text;
It's supposed to access the values in those cells when UPDATE button is pushed. However, using MessageBox.Show , comes back blank.
Anyone have any idea how I can capture those values after hitting Edit, then the default UPDATE button?
I've tried to make that Winforms Datagrid usable for "write through" in the past, by implementing an DataGridView subclass (this allows you to access everything) but since immutable databases and queue transactions came into view, my Access-flavour DataGrid did not survive modern paradigm. Nowadays I tend to support ASP.NET MVC 5 to "edit" databases.
Anyway have you considered to connect a DataSource ? You don't have to access cells.. you can update using a connection like
private SqlDataAdapter daGrid = new SqlDataAdapter();
and this type of approach, you will have to fill in the details yourself, the complete code consists of several classes and is too large to post,
protected void dataGridView1_KeyUp(object sender, KeyEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
/// .. perform actions according to keyboard events ..
/// .. for example below one ..
}
public override void UpdateAfterEditGrid(DataSet ds, DataGridView dataGridView1, bool DoRestoreCursor)
{
if (daGrid != null)
{
if (conn.State == ConnectionState.Closed) conn.Open();
dataGridView1.EndEdit();
try
{
if (ds == null)
{
//DataGridView dgv = dataGridView1;
//Console.WriteLine("Go datasource update .. " + dgv[cColumnIndex, cRowIndex].Value);
daGrid.Update((DataTable)dataGridView1.DataSource);
}
else daGrid.Update(ds);
LoadGridRestoreCursor(dataGridView1, DoRestoreCursor);
}
catch { ErrorReporting.ErrorMessage("== cannot update this content =="); }
}
}
I am using Telerik's Radgridview. I currently have it populated with data from a test database and I do this by using a linq query when the window loads. I have two extra empty columns for users to enter in data, and what I want is to have any data entered into those columns be saved back to the database when the window is closed. That way the linq query will still work when I load the application back up again. I'm not entirely sure how to do this or what to put in my Window_Closing event. I've searched nearly every web article and thread on this and none of them have helped me with my particular issue. Specifically I am trying to update the DeductionInfo Table. This is my Window_Loaded event where I have my linq query that loads the data:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Loads queries from each of the designated data tables in BSI_Test
var customerQuery =
(from customer in testEntity.Customers
from deduction in testEntity.DeductionInfoes.DefaultIfEmpty()
join job in testEntity.Jobs
on customer.CID equals job.CID
join claim in testEntity.Claims
on job.JID equals claim.JID
select new DataProperties
{
Customer_Name = customer.CName,
Job_Name = job.JName,
Claim_No = claim.CLNumber,
Check_No = deduction.checkNo,
Check_Date = deduction.checkDate
})
.OrderBy(c => c.Customer_Name);
//Populates the Telerik data grid with data.
gridView.ItemsSource = customerQuery.ToList();
}
This is what I tried in my Window_Closing event which didn't seem to work, and I was wondering if anyone could help me understand how to do this:
DataTable ds = new DataTable();
public void Window_Closing(object sender, CancelEventArgs e)
{
SqlConnection con = new SqlConnection("Data Source = databaseserver; Database = database; User ID = sampleUsername; Password = SamplePassword; Integrated Security = False;");
con.Open();
SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM DeductionInfo", con);
adapter.Fill(ds);
DataTable dt = ds.Tables[0];
gridView.ItemsSource = dt;
con.Close();
}
The DeductionInfo table is null by the way, since this data will be used to fill it up.
I am currently working on a database system. In the system a user can search for a specific member using their ID. Searching for them filters all DataGridView results to just that specific member.
private void button3_Click(object sender, EventArgs e)
{
dataGridView1.ReadOnly = false;
using (SqlConnection con = new SqlConnection(constring))
{
int id = Convert.ToInt32(textBox1.Text);
con.Open();
DataTable FindAaron = new DataTable();
SqlDataAdapter adapt = new SqlDataAdapter("SELECT * FROM MembersTable WHERE MemberID =" + id, con);
adapt.Fill(FindAaron);
dataGridView1.DataSource = FindAaron;
con.Close();
}
}
This code filters the DataGridView results down to one row from the table 'MembersTable'. The user can now physically click on the table cell and edit the data as much as they want. Once they are finished they hit a 'Save Changes' button which I want to save the changes they made, update the source table and refill the DataGridView with all the members, now with updated info. This is the code I have behind the 'Save Changes' button at the moment.
try
{
//MemberClass.UpdateMember();
this.membersTableTableAdapter.Update(mainDatabaseDataSet.MembersTable);
dataGridView1.Refresh();
MessageBox.Show("Details updated");
}
catch
{
MessageBox.Show("An error has occured");
}
This unfortunately does not update the DataGridView in the form to display all the updated data or save the data that has been edited back to the Sql table. Have puzzled over this for a few days and can't figure out what I'm doing wrong. Any and all help is much appreciated.
Actually there is no connection seen between membersTableTableAdapter and adapt or mainDatabaseDataSet.MembersTable and FindAaron.
Try as following;
//Get the changed data
DataTable changes = FindAaron.GetChanges();
if (changes != null)
{
//Update data
adapt.Update(changes);
}
I'm trying to create a two-datagridview Master-Detail form to display the results of an SQL statement, but appear to have an added complication in that the two results I want to display are from the same table: I want just the IDs to appear in the top grid, and then detail from the rest of the table about the same ID to appear in the bottom grid. If I'm using the wrong method, then could someone please point me in the wrong direction?
My current problem is that the code gets to the DataRelation Rel = new DataRelation.... and displays the form (with both DataGrids blank) at that point, rather than executing the rest of the code.
I've pasted the full version below:
private void Form1_Load(object sender, EventArgs e)
{
SpContain.Panel1.Controls.Add(masterDataGridView);
SpContain.Panel2.Controls.Add(detailsDataGridView);
masterDataGridView.DataSource = masterBindingSource;
detailsDataGridView.DataSource = detailsBindingSource;
GetData();
}
private void GetData()
{
string ConnStr = "Server=TradarUAT\\uattradar; Integrated Security=SSPI; Initial Catalog=TradeFiles;";
SqlConnection Conn = new SqlConnection(ConnStr);
DataSet Data = new DataSet();
Data.Locale = System.Globalization.CultureInfo.InvariantCulture;
SqlDataAdapter masterDataAdapter = new SqlDataAdapter("Select MasterReference from [TradeFiles].[dbo].[OMG-Rejects] GROUP BY MasterReference", Conn);
masterDataAdapter.Fill(Data, "[TradeFiles].[dbo].[OMG-Rejects]");
SqlDataAdapter detailDataAdapter = new SqlDataAdapter("Select ImportedDT,TypeIndicator,FileNumber,MasterReference,ClientAlocRef,VersionNumber,DateTimeStamp,ErrorID,ErrorKey,ErrorTxt,ErrorParamType,ErrorParamValue from [TradeFiles].[dbo].[OMG-Rejects]", Conn);
detailDataAdapter.Fill(Data, "[TradeFiles].[dbo].[OMG-Rejects]");
DataRelation Rel = new DataRelation("RejectDetail",
Data.Tables[0].Columns["MasterReference"], Data.Tables[1].Columns["MasterReference"]);
Code stops executing on the above line
Data.Relations.Add(Rel);
masterBindingSource.DataSource = Data;
masterBindingSource.DataMember = "[TradeFiles].[dbo].[OMG-Rejects]";
detailsBindingSource.DataSource = masterBindingSource;
detailsBindingSource.DataMember = "RejectDetail";
}
Managed to solve this by creating a view on the SQL server that mimicked the first select statement I was trying to acheive. Then I just referenced the view in the masterDataAdapter, and retrieved the rest of the information from the underlying table in the detailDataAdapter.