spliting large query string in acess - c#

I had a long query in access and trying to make it into multiple lines so that i can check them during my debugging and I tried the steps which I found through google and its failing with the information shown below.
public DataSet showallCompanyPaymentbyjobcode(int jobpk ,int confirmquotationpk)
{
string query=SELECT companypaymentmastertable.paymentpk, companypaymentmastertable.cmpinvoice, companypaymentmastertable.jobcode, companypaymentmastertable.customercode, confirmquotationmastertable.quotationcode, companypaymentmastertable.customerName, companypaymentmastertable.ischeque, companypaymentmastertable.isCash, companypaymentmastertable.amount, companypaymentmastertable.chequenumber, companypaymentmastertable.bankname, companypaymentmastertable.chequedate, companypaymentmastertable.chequereleasedate, companypaymentmastertable.companypaymentdate
FROM confirmquotationmastertable INNER JOIN companypaymentmastertable ON confirmquotationmastertable.confirmpk=companypaymentmastertable.confirmpk
WHERE (((companypaymentmastertable.confirmpk)=[?]) AND ((companypaymentmastertable.jobpk)=15));
OleDbDataAdapter dAdapter = new OleDbDataAdapter(query, Program.ConnStr);
DataSet ds = new DataSet();
dAdapter.Fill(ds, "tblpayview");
if (ds.Tables.Count <= 0)
{
ds = null;
}
return ds;
}
in another class i called it
public void fillpaymenttable()
{
DataSet ds= new DataSet();
ds= companytransaction.showallCompanyPaymentbyjobcode(cmbjobcode.SelectedValue,cmbQuotationcode.SelectedValue);
tblpaymentview.DataSource = ds.Tables["tblpayview"].DefaultView;
if (ds.Tables.Count <= 0)
{
lblstatus.Text = "No Payment Details Present";
clearcontrols();
}
}
Is there any way to split the query and whether this function work if dataset called like this?

If you're just wanting to actually split the code up into separate lines, use a StringBuilder? Note that this wouldn't be the case if you were passing parameters to the query as you'd be vulnerable to SQL injections
var query = new StringBuilder();
query.Append("SELECT companypaymentmastertable.paymentpk, companypaymentmastertable.cmpinvoice, ");
query.Append("companypaymentmastertable.jobcode, companypaymentmastertable.customercode, ");
query.Append("confirmquotationmastertable.quotationcode, companypaymentmastertable.customerName, ");
query.Append("companypaymentmastertable.ischeque, companypaymentmastertable.isCash, ");
query.Append("companypaymentmastertable.amount, companypaymentmastertable.chequenumber, ");
query.Append("companypaymentmastertable.bankname, companypaymentmastertable.chequedate, ");
query.Append(" companypaymentmastertable.chequereleasedate, companypaymentmastertable.companypaymentdate ");
query.Append("FROM confirmquotationmastertable INNER JOIN companypaymentmastertable ");
query.Append("ON confirmquotationmastertable.confirmpk=companypaymentmastertable.confirmpk ");
query.Append("WHERE (((companypaymentmastertable.confirmpk)=[?]) ");
query.Append("AND ((companypaymentmastertable.jobpk)=15))");

This would be more efficient than using a stringbuilder, because the string concatenation will be performed at compile time, not at run time:
string query="SELECT companypaymentmastertable.paymentpk, companypaymentmastertable.cmpinvoice, "
+ "companypaymentmastertable.jobcode, companypaymentmastertable.customercode, "
+ "confirmquotationmastertable.quotationcode, companypaymentmastertable.customerName, "
+ "companypaymentmastertable.ischeque, companypaymentmastertable.isCash, companypaymentmastertable.amount, "
+ "companypaymentmastertable.chequenumber, companypaymentmastertable.bankname, companypaymentmastertable.chequedate, "
+ "companypaymentmastertable.chequereleasedate, companypaymentmastertable.companypaymentdate "
+ "FROM confirmquotationmastertable INNER JOIN companypaymentmastertable ON "
+ "confirmquotationmastertable.confirmpk=companypaymentmastertable.confirmpk "
+ "WHERE (((companypaymentmastertable.confirmpk)=[?]) AND ((companypaymentmastertable.jobpk)=15));"
Alternatively, you could use a "verbatim string":
string query= #"SELECT companypaymentmastertable.paymentpk, companypaymentmastertable.cmpinvoice,
companypaymentmastertable.jobcode, companypaymentmastertable.customercode,
confirmquotationmastertable.quotationcode, companypaymentmastertable.customerName,
companypaymentmastertable.ischeque, companypaymentmastertable.isCash, companypaymentmastertable.amount,
companypaymentmastertable.chequenumber, companypaymentmastertable.bankname, companypaymentmastertable.chequedate,
companypaymentmastertable.chequereleasedate, companypaymentmastertable.companypaymentdate
FROM confirmquotationmastertable
INNER JOIN companypaymentmastertable ON confirmquotationmastertable.confirmpk=companypaymentmastertable.confirmpk
WHERE (((companypaymentmastertable.confirmpk)=[?]) AND ((companypaymentmastertable.jobpk)=15));";

Related

Condition statements for a single row data value in a database

I am using C# to create a windows form.
I am trying to set a condition statement for a particular value that is retrieved from my database by the onclick of a button. The datatype of the column is 'integer'.
Below is my code:
string checkquantity = "SELECT `inventory_item`.`Item_Quantity_Available`FROM `inventory_item` , `patient`, `out_treatment`WHERE `inventory_item`.`Item_ID` = `out_treatment`.`Inventory_ID`AND `patient`.`Patient_ID` = `out_treatment`.`Patient_ID`AND `out_treatment`.`Patient_ID`= '" + pid + "' ";
MySqlCommand selectout = new MySqlCommand(checkquantity, connect);
MySqlDataAdapter selectdata = new MySqlDataAdapter(checkquantity, connect);
DataTable selecttable = new DataTable();
selectdata.Fill(selecttable);
DataSet ds = new DataSet();
selectdata.Fill(selecttable);
selectdata.Fill(ds);
int i = ds.Tables[0].Rows.Count;
if ( i <= 0)
{
MessageBox.Show("Out of Stock");
}
I'm new with c#.
I don't think the int i = ds.Tables[0].Rows.Count; is the right way.
Any help is much appreciated.
First of all, like #Flydog57 said, you should not concatenate your sql query. The best way is to use parameters, for example:
string checkquantity = "SELECT i.Item_Quantity_Available " +
" FROM inventory_item i JOIN out_treatment t ON i.Item_Id = t.Inventory_ID " +
" JOIN patient p ON t.Patient_ID = p.PatiendID " +
" WHERE t.Patient_ID = #Patiend_ID";
MySqlCommand selectout = new MySqlCommand(checkquantity, connect);
// set the parameter value
selectout.Parameters.AddWithValue("#Patiend_ID", patient_id_value);
MySqlDataReader rdr = cmd.ExecuteReader();
if (rdr.Read())
{
if ((int)rdr["Item_Quantity_Available"] == 0)
MessageBox.Show("Out of Stock");
}
In second place, you could use a MySqlDataReader to verify that Item_Quantity_Available is equal to 0, like in the previous example. Otherwise, If you just wants to verify if there is data, the condition could be something like that:
if (!rdr.Read())
{
MessageBox.Show("Out of Stock");
}
The third improvemente is to join tables with the join clause.

C# NpgsqlCommand - AddWithValue is not substituting

So let me first off state that I know there are other questions with the same issue--I've read most of them and tried different things... Nothing worked.. So please don't close because of "Duplicate" because those ARE NOT working for me.
I am also using Postgres as my database.
Thanks for assistance in advanced.
public static string RetrieveEntry(string table, string lookup)
{
Console.WriteLine("RetrieveEntry");
if (!IsConnected())
{
return "Request Failed";
}
string str = "No poll were found that contained that info.";
string sqlstring = "SELECT * FROM "+table+" WHERE topic = '#t' OR description LIKE '#d' OR started_by = '#sb'";
NpgsqlCommand sql = new NpgsqlCommand(sqlstring,conn);
sql.Parameters.AddWithValue("#t", lookup);
sql.Parameters.AddWithValue("#d", "%" + lookup + "%");
sql.Parameters.AddWithValue("#sb", lookup);
NpgsqlDataAdapter adap = new NpgsqlDataAdapter(sqlstring,conn);
DataSet ds = new DataSet();
adap.Fill(ds);
Console.WriteLine("Table: "+ds.Tables[0].TableName+"; Tables: "+ds.Tables.Count+"; Rows: "+ds.Tables[0].Rows.Count);
if (ds.Tables[0].Rows.Count > 0) str = ""; //Remove default string
foreach (DataRow dr in ds.Tables[0].Rows)
{
str += "Topic:\t" + dr["topic"] +
"\nDesc:\t" + dr["description"].ToString().Substring(0, Math.Min(25, dr["description"].ToString().Length)) + "\n\n";
}
return str;
}
Would using a reader fix the issue?
ds.Load(NpgsqlDataReader reader = sql.ExecuteReader(CommandBehavior.CloseConnection));
from this answer
I know it's a bit late, but I really think You shouldn't use the # character in the AddWithValue parameter.
Something like:
sql.Parameters.AddWithValue("t", lookup);
sql.Parameters.AddWithValue("d", "%" + lookup + "%");
sql.Parameters.AddWithValue("sb", lookup);

Executing a query with no search term causes System.StackOverflow Exception in System.Runtime.Serialization.dll

I 'm dealing with a query which results in above mentioned error when called with no or limited search string.
The table is 30k records big and when the query is fired with no search string I would expect the database to return all records and have Visual Studio put them in a table (ASP.net), however, if the query is fired like above the StackOverflow error is returned :(
If I fire the query with a more specific search string the script seems to work normal and results are being returned as expected.
I have been googling and all seems to point to an infinite loop or recursion but returning records make me believe it might be another problem.
The query:
SqlConnection conn = new SqlConnection(_cstring);
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
conn.Open();
SqlDataReader dr;
if (mode == "zoek_met_zoekterm")
{
cmd.CommandText = "select W1.id, W1.soort_brief, W1.omschrijving, W1.referentie, W1.url, W1.factuur, W3.naam, W3.klantnummer, W4.omschrijving AS w4_omschr, W4.referentie AS w4_ref, substring(W1.referentie,6,2) as w1_jaar, W1.parent AS w1_parent from brief W1 left join brief W4 on W1.parent = W4.id join klant W3 on W3.klantnummer = W1.klantnummer where W1.referentie in (select referentie from brief where substring(referentie,6,2) = #jaar) and (W3.klantnummer like #zoekterm or W1.referentie like #zoekterm or W1.omschrijving like #zoekterm or W3.naam like #zoekterm or W4.omschrijving like #zoekterm) order by W1.id";
cmd.Parameters.Clear();
cmd.Parameters.Add("#zoekterm", SqlDbType.VarChar).Value = "%" + (string)parameters["zoekterm"] + "%";
string jaar = parameters["jaar"].ToString();
jaar = jaar.Substring(2, 2);
cmd.Parameters.Add("#jaar", SqlDbType.VarChar).Value = jaar;//(Int32)parameters["jaar"];
base.LogQuery(cmd);
dr = cmd.ExecuteReader();
while (dr.Read())
{
CBrief brief = new CBrief();
brief.Id = dr.GetInt32(0);
brief.SoortBrief = (Enums.SoortBrief)dr.GetInt32(1);
brief.Omschrijving = Functies.Decrypt(dr.GetString(2), EncryptData);
brief.Referentie = Functies.Decrypt(dr.GetString(3), EncryptData);
brief.Url = Functies.Decrypt(dr.GetString(4), EncryptData);
brief.Factuur = (Enums.SoortDocument)dr.GetInt32(5);
brief.Klantnummer = dr.GetInt32(7);
if (dr.GetString(2).Length == 0)
{
if (!dr.IsDBNull(9) && !dr.IsDBNull(8))
brief.Omschrijving = dr.GetString(9) + " " + dr.GetString(8);
}
ret_value.Add(brief);
}
dr.Close();
dr.Dispose();
}
And the function that calls the query:
public List<CBrief> GetBriefOverzicht(string zoekterm, int jaar)
{
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("zoekterm", zoekterm);
parameters.Add("jaar", jaar);
if (zoekterm.Length == 0)
{
return _dal.brief_search(parameters, "geen_invoer");
}
return _dal.brief_search(parameters, "zoek_met_zoekterm");
}
And last but not least the function that builds the table to display in the web application:
protected void Bzoeken_Click(object sender, EventArgs e)
{
string zoekterm = TBzoekterm.Text;
DateTime nu = DateTime.Now;
int jaar = nu.Year;
List<CBrief> brieven = br_rbs.GetBriefOverzichtWijzigen(zoekterm);
StringBuilder overzicht = new StringBuilder("<table class=\"tabel-beheer-1\">");
foreach (CBrief b in brieven)
{
List<CBijlage> bijlagen = new List<CBijlage>();
CKlant k = sec.GetKlant(b.Klantnummer);
string klantnaam = k.Naam;
string richting = "";
if (b.OmschrijvingAanwezig == true)
{
bijlagen = br_rbs.GetBijlagenBrieven(b.Id);
}
if (b.SoortBrief == Enums.SoortBrief.Inkomend) richting = "van: "; else richting = "naar: ";
// MG10082017 Ik heb hier twee icoontjes in elkaar geflanst om te testen. Deze moeten nog aangepast worden zodat ze in het geheeel passen.
overzicht.AppendLine("<tr><td><img src=\"/images/bg/document.jpg\" alt=\"open document\"></td><td><img src=\"/images/bg/detail.jpg\" alt=\"details\"></td><td><b>" + b.Referentie + "</b></td><td><i>" + b.SoortBrief.ToString() + " " + richting + "</i> " + klantnaam + "</td><td><b> " + b.Factuur.ToString() + ":</b> " + b.Omschrijving /*+"</td><td>"*/);
if (bijlagen.Count > 0)
{
foreach (CBijlage bijl in bijlagen)
{
overzicht.AppendLine("</br> " + bijl.Naam + "");
}
}
}
overzicht.AppendLine("</td></tr></table>");
Loverzicht.Text = overzicht.ToString();
}
The error usually points to: System.Web.dll or w3wp.exe (when not ran in debug mode). If my assumption is wrong and it seems to be an infinite loop or recursion, how am I going to find this?
The query works flawless in MS-SQL management console.
The Problem is not an infinite loop!
The Problem lies in the UI.
You can't display 30k units at once without a StackOverflow-Exception.
You should call pages of maybe 20 or 30 units at once with an pageIndex.
This way, your application will perform better and avoid such errors.

C# datagrid not populating and no error

My first problem is that i have a method private void FillGeneralLedger(), i put the method in a button on click event to fill a datagridview dgvGeneralLedger my problem is when i run i am not getting an error and the dgv is remaining empty.
My Second problem is i would like to use the same connection but have 5 commands all the same just different account numbers eg in the example below the account below is '8200030' i would like to do the same for '8200031','8200032'
private void FillGeneralLedger()
{
SqlConnection conn = new SqlConnection(sConnectionString);
try
{
DataSet dataset = new DataSet();
SqlCommand command = new SqlCommand("Select Ddate as Date" +
", etype" +
", Refrence" +
", linkacc as ContraAcc" +
", Description" +
", sum(case when amount > 0 then amount else 0 end) as Debits" +
", sum(case when amount < 0 then amount else 0 end) as Credits" +
", sum(amount) as Cumulative" +
" FROM dbo.vw_LedgerTransactions " +
" WHERE accnumber = '8200030'" +
" AND DDate BETWEEN '2016-04-01 00:00:00' AND '2016-04-30 00:00:00'" +
" AND DataSource = 'PAS11CEDCRE17'" +
" group by Ddate, etype, Refrence, linkacc, Description, Amount", conn);
SqlDataAdapter adapter = new SqlDataAdapter(command);
conn.Open();
command.ExecuteNonQuery();
adapter.Fill(dataset);
if (dataset.Tables[0].Rows.Count != 0)
{
lstGeneralLedger = new List<ReportDataClasses.GeneralLedger>();
foreach (DataRow row in dataset.Tables[0].Rows)
{
ReportDataClasses.GeneralLedger newGeneralLedger = new ReportDataClasses.GeneralLedger();
newGeneralLedger.Ddate = row[0].ToString();
newGeneralLedger.etype = row[1].ToString();
newGeneralLedger.refrence = row[2].ToString();
newGeneralLedger.linkacc = row[3].ToString();
newGeneralLedger.Description = row[4].ToString();
newGeneralLedger.debit = decimal.Parse(row[5].ToString());
newGeneralLedger.credit = decimal.Parse(row[6].ToString());
newGeneralLedger.cumulative = decimal.Parse(row[7].ToString());
lstGeneralLedger.Add(newGeneralLedger);
}
dgvGeneralLedger.DataSource = dataset;
dgvGeneralLedger.Columns[0].Visible = false;
pdfCreator.AddGeneralLedgerPage(lstGeneralLedger, 1);
}
}
catch (Exception ex)
{
MessageBox.Show("Application Error. err:" + ex.ToString());
}
finally
{
conn.Close();
}
}
Why do you use a DataSet when you only need a single DataTable, this doesn't make any sense. Just use one DataTable:
DataTable dataTableSource = new DataTable();
adapter.Fill(dataTableSource);
// .. cotinue your code
dgvGeneralLedger.DataSource = dataTableSource;
Account Number issue:
You can use SqlParameter instead of hard-coding the value. Like this:
command.Parameters.AddWithValue("#acc", "8200030");
dataTableSource.Load(command.ExecuteReader())
// .. store results ..
// second account
command.Parameters["#acc"].Value = "8200031";
dataTableSource.Load(command.ExecuteReader())
// continue with the rest
But you need to change your query to be like this:
"... WHERE accnumber = #acc ...."

How to use Linq instead of SQL Injection query for custom search

I would like to use Linq instead of below hardcoded Sql Injection to search from SqlServer DATABASE TABLES. How to retrieve Dynamically generated web controls input texts in C# Linq and replace the entire Sql injection in Linq for searching.
My C# code:
protected void Search_Button_Click(object sender, EventArgs e)
{
try
{
Table maintable = Select.FindControl("dynamic_filter_table_id") as Table;
int rc = maintable.Rows.Count;
if (rc == 1)
{
DropDownList D1 = maintable.FindControl("MainDDL") as DropDownList;
if (D1.SelectedValue.Contains("decimal"))
{
TextBox T1 = maintable.FindControl("txtbox1") as TextBox;
TextBox T2 = maintable.FindControl("txtbox2") as TextBox;
SqlDataAdapter sql = new SqlDataAdapter("SELECT F.Col1,F.Col2,V.COL1, col2,col3, col4 , col5, cl6 FROM TABLE1 as V , TABL2 as F WHERE V.Col1 = F.Col1 AND " + DDL1.SelectedItem.Text + " >= " + T1.Text + " AND " + DDl1.SelectedItem.Text + " <= " + T2.Text, con);
DataSet data = new DataSet();
sql.Fill(data);
con.Close();
Session["DataforSearch_DDL"] = data.Tables[0];
}
}
}
catch
{
ImproperSearch();
}
}
Why don't you just rewrite your query to be SQL-injection safe? LINQ won't give you any benefit.
You can achieve that by doing two things.
The first is to secure the column names. That is accomplished by specifying which characters is allowed for column names (more secure than trying to figure out what characters is not allowed). In this case I remove everything but letters and digits. If you have column names which contains underscore, just add that to the check.
The next thing is to use parameterized queries. Each ADO.NET driver has built in support for that, so you just have to specify the value using cmd.Parameters.AddWithValue. By doing so the value isn't part of the query string and hence there is no potential SQL injection.
using (var con = yourConnectionFactory.Create())
{
using (var cmd = new SqlCommand(con))
{
var safeKey1 = OnlyLettersAndDigits(DDL1.SelectedItem.Text);
var safeKey2 = OnlyLettersAndDigits(DDL2.SelectedItem.Text);
cmd.CommandText = "SELECT F.Col1,F.Col2,V.COL1, col2,col3, col4 , col5, cl6 " +
" FROM TABLE1 as V , TABL2 as F WHERE V.Col1 = F.Col1 " +
" AND " + safeKey1 + " >= #text1 " +
" AND " + safeKey2 + " <= #text2 ";
cmd.Parameters.AddWithValue("text1", T1.Text);
cmd.Parameters.AddWithValue("text2", T2.Text);
var adapter = new SqlDataAdapter(cmd);
var data = new DataSet();
sql.Fill(data);
Session["DataforSearch_DDL"] = data.Tables[0];
}
}
public string OnlyLettersAndDigits(string value)
{
var stripped = "";
foreach (var ch in value)
{
if (char.IsLetterOrDigit(ch))
stripped += ch;
}
return stripped;
}
You can use store procedure for customer search, It will work for both ADO.Net and LINQ approach. Just create a SP and add it to your DBML file very simple.
Here is the link how you can use SP in LINQ
http://www.mssqltips.com/sqlservertip/1542/using-stored-procedures-with-linq-to-sql/

Categories

Resources