Find bankbalance with Dataset - c#

As a side project I am developing a basic banking system using C# and WPF to create the forms.
At the moment, I have four forms and two different global classes.
The forms are:
Welcome Page; This form is used to create an initial dataset stored in BankData.cs. All of my database table is stored here - the table is called UserData.
Validate User; This form is where the user enters their account number and pin. I do some validation here to ensure it's 6 characters and only integers etc. I then call the Global.cs class which has a method to option the DB and log the user in (Check if it matches). If it does, then I store the AccountNumber and PIN in the BankData.cs class.
Options Form; This form is simply just three buttons, at the moment going to the Display Balance form.
Display Balance; This form should display the current Balance and the Remainign Withdrawal limit for that user (£250 pounds, although this goes down when they withdraw more. They can't withdraw more than this).
My problem is when I am trying to display the Current Balance. I try to query the dataset using linq by converting it to a datatable. However, when I try to display the balance I am getting this instead of a balance:
System.Linq.Enumerable+WhereSelectEnumerableIterator'2[System.Data.DataRow,System.String]
I am converting everything to a string and it doesn't change this message. I also tried returning the integer value of the balance but this causes compilier errors.
I've attached the codethat should show the balance on the label from the Options Form class, and the code that finds the balance in BankData.cs
BankData.cs
public static string FindBalance()
{
DataTable dt = new DataTable();
dt = ds.Tables[0];
var id = (from DataRow dr in dt.Rows
where (string)dr["AccountNo"] == accountNumber
select dr.Table.Rows[5].ToString());
//return dt.Rows[rowNum][columName].ToString();
return id.ToString();
}
DisplayBalance cs:
lblcurBal.Content = "Current Balance: " + BankData.FindBalance();
//Find the Balance of the Account Number here.
Please help.

Try This: a small change in your code
public static string FindBalance()
{
DataTable dt = new DataTable();
dt = ds.Tables[0];
var id = (from DataRow dr in dt.Rows
where dr["AccountNo"] == accountNumber
select dr["BalanceColumnName"]).FirstOrDefault();
return id.ToString();
}
EDIT:
This is what worked for Paul as he described in comments below :
public static string FindBalance()
{
DataTable dt = new DataTable();
dt = ds.Tables[0];
var id = (from DataRow dr in dt.Rows
where Convert.ToString(dr["AccountNo"]) == accountNumber
select dr["BalanceColumnName"]).FirstOrDefault();
return id.ToString();
}

You need to use id.FirstOrDefault(); in this particular case instead of id.ToString(); as return value since FirstOrDefault actualy gets data from your linq query and ToString is just query internal string representation.
In other words, value of variable id is not a result of query you've wrote, it is query itself. And FirstOrDefault retrieves first result form this query.

The problem is that id is an enumeration which is a collection of values, looks like you are expecting single value.
Assuming 6th column of your DataTable represents balance,
public static string FindBalance()
{
DataTable dt = new DataTable();
dt = ds.Tables[0];
var id = (from DataRow dr in dt.Rows
where (string)dr["AccountNo"] == accountNumber
select dr[5].ToString()).FirstOrDefault();
//return dt.Rows[rowNum][columName].ToString();
return id== null? "" : id;
}

You need to obtain the result from the collection, using something like FirstOrDefault()
return Convert.ToString(id.FirstOrDefault());
You are actually calling ToString on the iterator, and not actually obtaining the result.

I got this working based off of the solution by vedbhawsar.
By changing the code on the BankData.cs class to:
var id = (from DataRow dr in dt.Rows
where Convert.ToString(dr["AccountNo"]) == accountNumber
select dr["Balance"]).FirstOrDefault();
return id.ToString();
It allows my to display the balance of the user who has logged in.
Thanks a lot; now I just need to replicate this to take the Minimum Remaining Balance. Expect me back when it doesn't work lol.
Thanks again everyone who helped me come to this conclusion.

Related

Problem with format in C# with DataGridView and TextBox

I have a problem with format in C#.
I have a DataGridView and a TextBox. In this datagridview, there is a column: the single price (format int).
I want sum every elements of single price's column and insert the result into this textbox, but Visual Studio gives me a problem with format of string input ("Format of input's string is not correct").
this is the code than i used:
int TOT = 0;
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
TOT = TOT + Convert.ToInt32(dataGridView3.Rows[i].Cells[6].ToString());
}
textBoxTot.Text = Convert.ToString(TOT);
Can you help me with this bad error?
UPDATE:
I think that the problem now is another. I can't find the methods of MySql.Data.MySqlClient library that it can give me the result of query.
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
conn.closeConnection();
How is the command that give me the result of sumQuery. If i find this command, i can take the result of query and paste in textbox
If your datagridview is showing a datatable (I.e. your data is stored in a datatable) you can add a DataColumn to the datatable whose .Expression property is set to the string "SUM([Price])", where Price is the name of your numeric datatyped column holding the price info.
Now every row in the table will have the sum of the prices (the same value over and over again), so if you want to databind your textBox to this new column then it will always show the sum no matter which row is the current row (because all rows have the same value). It will also auto update without you having to do anything!
And if you're not using databinding to a datatable, I recommend that you do do it, because it represents good MVC practice of keeping your data in one thing (DataTable) and showing it in another (DataGridView) and keeping these concerns separate
It would look something like this, as a quick example:
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Price", typeof(int));
dt.Columns.Add("CalculatedTotal", typeof(int)).Expression = "SUM([Price])";
dt.Rows.Add("Apples", 100);
dt.Rows.Add("Oranges", 200);
BindingSource bs = new BindingSource();
bs.DataSource = dt;
WhateverDataGridView.DataSource = bs;
totalTextBox.DataBindings.Add(new Binding("Text", bs, "CalculatedTotal", true));
Here we have a data model (the datatable) where we keep our data. It has a couple of things we can set directly, and an third column that calculates based on the existing prices in all the table. If you look at this in the datagridview (assuming you have autogeneratecolumns turned on) you'll see that both rows have 300 for the CalculatedTotal, but they have individual amounts for price. There is a device called a BindingSource that sits between the datatable and the UI controls; you don't have to have one but it makes certain things easier regards updating controls when the data changes, and it maintains a concept of "current" - essentially whatever the current row is you're looking at in the datagridview; it all helps to avoid having to ask the DGV for anything - we just let the user type into the DGV, and it shows the data out of the datatable. All our dealings can be with the datatable directly - if you wrote a button to loop through the table and double all the prices, the controls in the UI would just reflect the change automatically. The textbox is connected to the CalculatedValue column via databinding; whatever the current row is, the textbox will show the CalculatedValue. Because the CalculatedValue column has the same value on every row, and they always all update if any price changes, the total textbox will always show the total. Add another textbox bound to Name to see what I mean; as you click around the grid and select different rows to be the "Current" row, the Name will change but the total does not. In truth it is actually changing in the same way that Name is, it's just that because the actual numeric value is the same on every row the contents of the textbox look like they don't change
UPDATE: I think that the problem now is another. I can't find the methods of MySql.Data.MySqlClient library that it can give me the result of query.
public string sommaFattura(String costo)
{
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
conn.closeConnection();
}
How is the command that give me the result of sumQuery. If i find this command, i can take the result of query and paste in textbox
It is weird that you are first converting to a string and then to an int.
int TOT = 0;
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
if (!dataGridView3.Rows[i].IsNewRow &&
int.TryParse(dataGridView3.Rows[i].Cells[6].Value.ToString(), out int v))
TOT += v;
}
textBoxTot.Text = TOT.ToString();
EDIT: Edited for your updated question. You shouldn't ask question inside a question buy anyway:
string sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
decimal total = 0M;
using (MySqlConnection cn = new MySqlConnection(" your connection string here "))
using (MySqlCommand cmd = new MySqlCommand(sumQuery, cn))
{
cn.Open();
total = Convert.ToDecimal(cmd.ExecuteScalar());
cn.Close();
}
Console.WriteLine(total);

ComboBox Index Changed

Need to know: I am working with Windows Forms in Visual Studio and C#.
I have 5 comobobox's that I populate from SQL with the parts available in the DB. Part of the coding to it, one uses a DataTable and set the DataSource of the comboBox to that DataTable.
In this same DataTable via my SQL query, I have listed the cost of the part in the list. What I want to do is whichever part you pick from the dropdown list, the related price must show in the textbox next to it.
I am trying to use the comboBox1_SelectedIndexChanged for this, but the problem I run into is as soon as the DataSource gets set to the DataTable while the form's initial loading, it gets picked up as a Index change and the comboBox1_SelectedIndexChanged wants to run. But at this point in time, the SelectedIndex Value is null due to it still loading, causing it to give me a exception cast error.
how can I work around this?
DataTable SparePart = new DataTable() is declared outside the function to make it available as "public" so that the comboBox1_SelectedIndexChanged can access it.
Then I have this code to populate the comboBox:
//Read Status info from DB
SqlDataAdapter SparePartReader = new SqlDataAdapter(SQLSparePartDropbox);
SparePartReader.Fill(SparePart);
comboBoxFinJCSpares1.DataSource = SparePart;
comboBoxFinJCSpares1.DisplayMember = "DisplayMember";
comboBoxFinJCSpares1.ValueMember = "PartID";
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
and then I have this for the comboBoxFinJCSpares1_SelectedIndexChanged:
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
enter image description here
The solution is as easy as making one boolean variable and call it formLoaded.
Set it to false, then set it to true after the form loads.
Put your code for populating combobox inside if statement and that should do it
Cheers ~ ChenChi
demo:
//Read Status info from DB
if(formLoaded)
{
SqlDataAdapter SparePartReader = new SqlDataAdapter(SQLSparePartDropbox);
SparePartReader.Fill(SparePart);
comboBoxFinJCSpares1.DataSource = SparePart;
comboBoxFinJCSpares1.DisplayMember = "DisplayMember";
comboBoxFinJCSpares1.ValueMember = "PartID";
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
}
Thanks guys, the "SelectedChangeCommitted" option suggested by Marcel Hoekstra solved my problem.

Get the highest value from a given column in a datatable

I have a datatable that has a column "Pending Approval Number". I need to get the highest number in that column to display to a user as the next available. I have seen some examples of how to do this but I have not been able to get them to work. I know i could loop each DataRow in the DataTable and check the value and store it if it is higher than the last. But I know there has to be a better way.
Here is how the DataTable is filled.
strSQL = "Select * from JobInvoice";
DataTable dtApprovalNumber = new DataTable();
MySqlDataAdapter daApprovalNumber = new MySqlDataAdapter(strSQL, conn);
daApprovalNumber.Fill(dtApprovalNumber);
A change to the SQL query or code to pull it from the datatable are both welcome.
EDIT: After getting the solution for my original numeric column, I found the second column that I need to do this for is string. The solution was also provided below.
If You want to get highest Value from DataTable in code not in sql, then You can just use linq like below:
int highestNumber = dtApprovalNumber.AsEnumerable().Max(x => x.Field<int>("SomeIntegerColumn");
EDIT.
According to Your comment - if You want to calculate max value from a string column which holds numbers(don't get it why) You can go with something like that:
int highestNumber = dtApprovalNumber.AsEnumerable().Max(x => int.Parse(x.Field<string>("SomeStringColumn")));
Please Note that if any of those string values is not convertable it will fail then You will have to do it other way.
EDIT.2
Since I've just tried it I'll share with You - the situation when You have string Column and You are not sure if all of them are convertable(for example some might be empty). See below:
int tempVariable;
int highestNumber = dt.AsEnumerable()
.Where(x => int.TryParse(x.Field<string>("SomeColumn"), out tempVariable))
.Max(m => int.Parse(m.Field<string>("SomeColumn")));
Select max(`Pending Approval Number`) from JobInvoice
You can do a maxvalue + 1 to show it as next available number.

DataTable find or if not found insert row

I have a DataTable dt with 2 columns. First col (call it CustomerId) is unique and doesn't allow nulls. the second one allows nulls and is not unique.
From a method I get a CustomerId and then I would like to either insert a new record if this CustomerId doesn't exist or increment by 1 what's in the second column corresponding to that CustomerId if it exists.
I'm not sure how I should approach this. I wrote a select statement (which returns System.Data.DataRow) but I don't know how to test whether it returned an empty string.
Currently I have:
//I want to insert a new row
if (dt.Select("CustomerId ='" + customerId + "'") == null) //Always true :|
{
DataRow dr = dt.NewRow();
dr["CustomerId"] = customerId;
}
If the datatable is being populated by a database. I would recommend making the customerid a identity column. That way when you add a new row it will automatically create a new customerid which will be unique and 1 greater than the previous id (depending on how you setup your identity column)
I would check the row count which is returned from the select statement. Something like
I would also use string.Format...
So it would look like this
var selectStatement = string.Format("CustomerId = {0}", customerId);
var rows = dt.Select(selectStatement);
if (rows.Count < 1){
var dr = dt.NewRow();
dr["CustomerId"] = customerId;
}
This is my method to solve similar problem. You can modify it to fit your needs.
public static bool ImportRowIfNotExists(DataTable dataTable, DataRow dataRow, string keyColumnName)
{
string selectStatement = string.Format("{0} = '{1}'", keyColumnName, dataRow[keyColumnName]);
DataRow[] rows = dataTable.Select(selectStatement);
if (rows.Length == 0)
{
dataTable.ImportRow(dataRow);
return true;
}
else
{
return false;
}
}
The Select Method returns an array of DataRow objects. Just check if its length is zero (it's never null).
By the way, don't write such statements in the code directly as in this example. There's a technique for breaching your code's security called "SQL Injection", I encourage you to read the Wikipedia Article. In brief, an experienced user could write SQL script that gets executed by your database and potentially do harmful things if you're taking customerId from the user as a string. I'm not experienced in database programming, this is just "general knowledge"...

ASP.NET DATA TABLE Traverse Problem

I am getting the Data table a output from my DataAccess Layer.
In My Datatable I am getting users Name,Number,Qualification
I want to assign a users name,number,qualification to a textbox for a particular user id,
How can i do that.
Help
Suppose you got datatable dt from the DAL
Then
var row = from t in dt
where t["userId"]='userid'
select t;
since you got row related to a user now you can use it to assign to the textboxs
txtName.Text = row["Name"]
assuming the datatable has 1 row:
DataRow row = table.Rows[0];
textbox1.text = row["Name"];
textbox2.text = row["Number"];
and so on
if there are multiple rows in the datatable, you need to select the row with that particular used id
DataRow row = table.Select("ID=" + UserID.ToString());
You have to pay attention to NULL values and number of rows.
if (table.Rows.Count == 1)
{
DataRow row = table.Rows[0];
NameTextBox.Text = row.IsNull("name") ? string.Empty : row["name"];
NumberTextBox.Text = row.IsNull("number") ? string.Empty : row["number"];
}
else
{
// Deal with no rows from DL
}
Using ternary operator makes you sure, you delete content of TextBoxes in case you reload row within already filled up page.
Also you may consider to used typed dataset, and access to columns will be generated by xsd.exe.

Categories