Filtering DataView with multiple columns - c#

In my application I am using a dataview for having the filters to be applied where the filter options are passed dynamically.if there are 2 filter parameters then the dataview should be filtered for parameter1 and then by parameter two. I am using a method which is called in a for loop where I am setting the count to the total no.of parameters selected using a listbox but the filtering is done only for the last parameter.
Here is my code:
string str = "";
for (int i = 0; i < listbox.Items.Count; i++)
{
if (listbox.Items[i].Selected)
{
if (str != string.Empty)
{
str = str + "," + listbox.Items[i].Text;
}
else
{
str = str + listbox.Items[i].Text;
}
}
}
string[] items = str.Split(',');
for (int i = 0; i < items.Length; i++)
{
ApplyFilter(items[i],dv);
}
private DataView ApplyFilter(string str,DataView newdv)
{
newdv.RowFilter = "[" + str + "]=" + ddl.SelectedItem.ToString();
return newdv;
}
Please provide a suitable solution .
Thanks in advance...

You should apply your filter altogether, not one by one :
newdv.RowFilter = "Column1 = " + value1 + " AND Column2 = " + value2;
So you can change your code as :
string[] items = str.Split(',');
string filter = string.Empty;
for (int i = 0; i < items.Length; i++)
{
filter += items[i] + " = " + dropdown.SelectedValue;
if (i != items.Length - 1)
{
filter += " AND ";
}
}
newdv.RowFilter = filter;

I think you should build a complete filter string and then set this filter to your DataView.
For example:
StringBuilder sb = new StringBuilder()
for (int i = 0; i < listbox.Items.Count; i++) {
if (!listbox.Items[i].Selected) {
continue;
}
if (sb.Length > 0) {
sb.Append(" and ");
}
sb.AppendFormat("[{0}] = {1}", listbox.Items[i].Text, ddl.SelectedItem);
}
dv.RowFilter = sb.ToString();

DataView dv = new DataView(dt);
string filterText = "some search criteria";
dv.RowFilter = "Column1 + Column2 + Column3 Like '%" + filterText + "%'";

I had a similar problem - but i think solution will be the same for both of them. I have a datatable that needs to be filtered by 5 controls and if they aren't filled - it shouldn't be filtered.
List<string> allParams = new List<string>();
//here add fields you want to filter and their impact on rowview in string form
if (tsPrzelewyTxtOpis.Text != ""){ allParams.Add("Opis like '%" + tsPrzelewyTxtOpis.Text + "%'"); }
if(tsPrzelewyTxtPlatnik.Text != ""){ allParams.Add("Płacący like '%" + tsPrzelewyTxtPlatnik.Text + "%'"); }
if(tsPrzelewyDropDownKonto.Text != "") { allParams.Add("Konto = '" + tsPrzelewyDropDownKonto.Text + "'"); }
if (tsPrzelewyDropDownWaluta.Text != "") { allParams.Add("Waluta = '" + tsPrzelewyDropDownWaluta.Text + "'"); }
if (tsPrzelewyDropDownStatus.Text != "") { allParams.Add("Status = '" + tsPrzelewyDropDownStatus.Text + "'"); }
string finalFilter = string.Join(" and ", allParams);
if (finalFilter != "")
{ (dgvPrzelewy.DataSource as DataTable).DefaultView.RowFilter = "(" + finalFilter + ")"; }
else
{ (dgvPrzelewy.DataSource as DataTable).DefaultView.RowFilter = ""; }

Related

String.Format Method to align database output in a text file

I know there a some other questions related to mine but still they do not help me very much. I tried to understand the concept of the String.Format Method but i failed over and over again and still have no clue how to use it in my case. I know it is asked very much but if someone has an idea how to get the alignment in place i would appreciate it a lot.
I'm saving the output of different database tables to different text files. I want to align the "name" of the column to its "value". This makes very much sense because in some tables there a lot of "null" values and that leads to a poorly formatted output. Because the "null" is not exported to that file and therefore the values are moved to the left.
private void WriteSQLQueryOutputToTextFile(string DBUser, string DBUserPassword, string sqlQuery, string databaseName, string nameOfOutputFile)
{
string pathOfOutputFile = dWTestResult + "\\DatabaseUpgradeCheck\\" + nameOfOutputFile;
using (SqlConnection sqlCon = new SqlConnection("Data Source=" +
GetEnvironmentVariable.MachineName + "; Initial Catalog=" + databaseName + "; User ID=" + DBUser + "; Password=" + DBUserPassword + ";"))
{
SqlDataAdapter adapter = new SqlDataAdapter(sqlQuery, sqlCon);
try
{
sqlCon.Open();
DataSet dataset = new DataSet();
adapter.Fill(dataset, "nameOfDataset");
string currentLine = "";
foreach (var col in dataset.Tables[0].Columns)
{
currentLine += " " + col.ToString();
}
OutputHandler.AppendDataToFile(pathOfOutputFile, currentLine);
foreach (DataRow row in dataset.Tables[0].Rows)
{
currentLine = "";
foreach (var item in row.ItemArray)
{
currentLine += " " + item.ToString();
}
OutputHandler.AppendDataToFile(pathOfOutputFile, currentLine);
}
}
catch (Exception ex)
{
logger.Debug(ex, "Writing Database Output to the " + "\"" + nameOfOutputFile + "\"" + " file failed");
}
finally
{
sqlCon.Close();
}
}
}
string.Format is good when you know your required format in advance, less good if you have dynamic sources like the results of a query. Try something like this:
private void WriteSQLQueryOutputToTextFile(string DBUser, string DBUserPassword, string sqlQuery, string databaseName, string nameOfOutputFile)
{
string pathOfOutputFile = dWTestResult + "\\DatabaseUpgradeCheck\\" + nameOfOutputFile;
using (SqlConnection sqlCon = new SqlConnection("Data Source=" +
GetEnvironmentVariable.MachineName + "; Initial Catalog=" + databaseName + "; User ID=" + DBUser + "; Password=" + DBUserPassword + ";"))
{
SqlDataAdapter adapter = new SqlDataAdapter(sqlQuery, sqlCon);
try
{
sqlCon.Open();
DataSet dataset = new DataSet();
adapter.Fill(dataset, "nameOfDataset");
string currentLine = "";
var nameLengths = new int[dataset.Tables[0].Columns.Count];
var i = 0;
foreach (var col in dataset.Tables[0].Columns)
{
var colName = col.ToString();
nameLengths[i] = colName.Length;
currentLine += " " + colName;
i++;
}
OutputHandler.AppendDataToFile(pathOfOutputFile, currentLine);
foreach (DataRow row in dataset.Tables[0].Rows)
{
currentLine = "";
i = 0;
foreach (var item in row.ItemArray)
{
var field = item.ToString();
currentLine += " " + field.PadRight(nameLengths[i], ' ');
i++;
}
OutputHandler.AppendDataToFile(pathOfOutputFile, currentLine);
}
}
catch (Exception ex)
{
logger.Debug(ex, "Writing Database Output to the " + "\"" + nameOfOutputFile + "\"" + " file failed");
}
finally
{
sqlCon.Close();
}
}
}
If you get the length of the string representation of every column name and data value, you can work out the minimum width for each column and prepare a format string for that column which sets its minimum width.
Something like this:
using System;
using System.Data;
using System.Linq;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = SampleData();
// Prepare the column formats
int nCols = dt.Columns.Count;
var dataWidths = dt.Columns.Cast<DataColumn>().Select(x => x.ColumnName.Length).ToList();
foreach (DataRow d in dt.Rows)
{
for (int i = 0; i < nCols; i++)
{
dataWidths[i] = Math.Max(dataWidths[i], d.ItemArray[i].ToString().Length);
}
}
var colFormats = dataWidths.Select(x => $"{{0,{-x}}}").ToList();
//
var sb = new StringBuilder();
// Add the column names
sb.AppendLine(string.Join(" ", dt.Columns.Cast<DataColumn>().Select((x, i) => string.Format(colFormats[i], x.ColumnName))));
// Add in the data
foreach (DataRow d in dt.Rows)
{
sb.AppendLine(string.Join(" ", d.ItemArray.Select((x, i) => string.Format(colFormats[i], x))));
}
Console.WriteLine(sb.ToString());
Console.ReadLine();
}
static DataTable SampleData()
{
DataTable sdt = new DataTable();
string[] cn = "ARCHIVE DBDATETIME NEXTDOCID HIGHESTDISK SYSTEMTYPE FLAGS VERSION SINGLEUSER".Split(' ');
foreach (string n in cn)
{
sdt.Columns.Add(n);
}
DataRow drn = sdt.NewRow();
drn["ARCHIVE"] = "Hello";
drn["DBDATETIME"] = 1316859;
drn["NEXTDOCID"] = 1;
drn["HIGHESTDISK"] = "Nothing";
drn["SYSTEMTYPE"] = 1;
drn["FLAGS"] = "ABC";
drn["VERSION"] = "Hello";
drn["SINGLEUSER"] = 256;
sdt.Rows.Add(drn);
drn = sdt.NewRow();
drn["ARCHIVE"] = "Value longer than header";
// No value for drn["DBDATETIME"] etc.
drn["SINGLEUSER"] = 256;
sdt.Rows.Add(drn);
return sdt;
}
}
}
Sample output:
ARCHIVE DBDATETIME NEXTDOCID HIGHESTDISK SYSTEMTYPE FLAGS VERSION SINGLEUSER
Hello 1316859 1 Nothing 1 ABC Hello 256
Value longer than header 256

There is no row at position 2 C# Runtime Exception

I am retrieving data from db and displaying in Label. but the problem is that this cannot retrieve db tabel first row data. Its print Second row data. If i given the db first row c_code then it is given the Error "There is no row at position 2" Kindly please solve my problem.
Thanks you
private void Get_Purchasing_Amount()
{
try
{
string get_P_Amount = "";
double var_P_Amount = 0;
int var_C_Code = 0;
string query = "select c_code as 'code' from `db_vegetable`.`tbl_payment_master`";
DataTable dt_C_Code = method_Class.method_Class.FetchRecords(query);
if (dt_C_Code.Rows.Count > 0)
{
for (int i = 0; i <= dt_C_Code.Rows.Count; i++)
{
var_C_Code = Convert.ToInt32(dt_C_Code.Rows[i]["code"]);
if (var_C_Code.Equals(Convert.ToInt32(txt_Customer_Code.Text)))
{
if (check_All.Checked.Equals(true))
{
get_P_Amount = "SELECT IFNULL(`purchasing`,0) AS 'purchasing' FROM `db_vegetable`.`tbl_payment_master` WHERE `c_code` = " + txt_Customer_Code.Text + "";
}
else
{
string dt_Query = "select `id` as 'id' from `db_vegetable`.`tbl_order_details`";
DataTable dt_C_O = method_Class.method_Class.FetchRecords(dt_Query);
if (dt_C_O.Rows.Count > 0)
get_P_Amount = "SELECT IFNULL(SUM(t_price),0) as 'purchasing' FROM `db_vegetable`.`tbl_order_details` WHERE `c_code` = " + txt_Customer_Code.Text + " AND (`date` BETWEEN '" + txt_From_Date.Text + "' AND '" + txt_To_Date.Text + "')";
else
lbl_Purchasing_Amount.Text = "0";
}
DataTable dt = method_Class.method_Class.FetchRecords(get_P_Amount);
var_P_Amount = Convert.ToDouble(dt.Rows[0]["purchasing"]);
lbl_Purchasing_Amount.Text = var_P_Amount.ToString();
}
else
{
lbl_Purchasing_Amount.Text = "0";
}
}
}
else
{
lbl_Purchasing_Amount.Text = "0";
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I believe this is probably the issue:
for (int i = 0; i <= dt_C_Code.Rows.Count; ; i++) {...}
Please consider substituting foreach (DataRow row in dt_C_Code.Rows) { ...}
If it's important which row should logically come "first", then please consider using an order by clause in your SQL statement.
Now problem is solve the problem is that break key word.
private void Get_Purchasing_Amount()
{
try
{
string get_P_Amount = "";
double var_P_Amount = 0;
//int var_C_Code = 0;
string query = "select c_code as 'code' from `db_vegetable`.`tbl_payment_master`";
DataTable dt_C_Code = method_Class.method_Class.FetchRecords(query);
if (dt_C_Code.Rows.Count > 0)
{
for (int i = 0; i <= dt_C_Code.Rows.Count; i++)//these line generate error please check this
{
//var_C_Code = Convert.ToInt32(dt_C_Code.Rows[i]["code"]);
if (Convert.ToInt32(dt_C_Code.Rows[i]["code"]).Equals(Convert.ToInt32(txt_Customer_Code.Text)))
{
if (check_All.Checked.Equals(true))
{
get_P_Amount = "SELECT IFNULL(`purchasing`,0) AS 'purchasing' FROM `db_vegetable`.`tbl_payment_master` WHERE `c_code` = " + txt_Customer_Code.Text + "";
}
else
{
string dt_Query = "select `id` as 'id' from `db_vegetable`.`tbl_order_details`";
DataTable dt_C_O = method_Class.method_Class.FetchRecords(dt_Query);
if (dt_C_O.Rows.Count > 0)
get_P_Amount = "SELECT IFNULL(SUM(t_price),0) as 'purchasing' FROM `db_vegetable`.`tbl_order_details` WHERE `c_code` = " + txt_Customer_Code.Text + " AND (`date` BETWEEN '" + txt_From_Date.Text + "' AND '" + txt_To_Date.Text + "')";
else
lbl_Purchasing_Amount.Text = "0";
}
DataTable dt = method_Class.method_Class.FetchRecords(get_P_Amount);
var_P_Amount = Convert.ToDouble(dt.Rows[0]["purchasing"]);
lbl_Purchasing_Amount.Text = var_P_Amount.ToString();
break;
}
else
{
lbl_Purchasing_Amount.Text = "0";
}
}
}
else
{
lbl_Purchasing_Amount.Text = "0";
}
}
catch (Exception)
{
}
}

How to retrieve value from dynamic text box using C#?

I am using tree view in my web application, but I am using dynamic input text box when tree view data bind. The code is:
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
tables = node[0].ChildNodes[0].SelectNodes("col[#text='" + ds.Tables[0].Rows[i]["ModuleName"].ToString() + "']");
TreeNode MyRoot = new TreeNode();
string GUID = Guid.NewGuid().ToString();
MyRoot.Text = " " + ds.Tables[0].Rows[i]["ModuleName"].ToString() + " " + "<input type='text' id='" + GUID + "' />";
MyRoot.Value = ds.Tables[0].Rows[i]["ModuleName"].ToString();
if (RootNode != ds.Tables[0].Rows[i]["ModuleName"].ToString())
{
tv_GetMenu.Nodes.Add(MyRoot);
RootNode = ds.Tables[0].Rows[i]["ModuleName"].ToString();
var rows = from row in ds.Tables[0].AsEnumerable()
where row.Field<string>("ModuleName").Trim() == RootNode
select row;
DataTable dt = new DataTable();
dt = rows.CopyToDataTable();
if (dt != null)
{
if (dt.Rows.Count > 0)
{
for (int j = 0; j < dt.Rows.Count; j++)
{
string GUID1 = Guid.NewGuid().ToString();
TreeNode MyChild = new TreeNode();
if ((dt.Rows[j]["PageName"].ToString().Trim() != "Master Config") && (dt.Rows[j]["PageName"].ToString().Trim() != "Upload") && (dt.Rows[j]["PageName"].ToString().Trim() != "label configuration") && (dt.Rows[j]["PageName"].ToString().Trim() != "Dashboard Report"))
{
MyChild.Text = " " + dt.Rows[j]["PageName"].ToString() + " " + "<input type='text' id='" + GUID1 + "' value='" + dt.Rows[j]["PageName"].ToString() + "'/>";
MyChild.Value = dt.Rows[j]["Address"].ToString();
MyRoot.ChildNodes.Add(MyChild);
}
}
}
}
}
}
The above code is working properly, but when I run the application and enter value in dynamic created text box then I am not getting this text box value for saving at run time. How we can access this value at run time?

fetch data from two different tables on same textbox changed event

I want to fetch some data from two different tables PRO and OPN_STK , in some controls like textboxs and datagridview . when i am selecting data from one table i.e. PRO ,the code is working perfect but when i applied same code just next to it , in same event for fetching data from another table i.e. OPN_STK it throws exception "object refrence not set to an instance of object" . I tried to know about the problem but now I'm blank , this is what I did ,
private void comboProname_TextChanged(object sender, EventArgs e)
{
dataGridView3.Rows.Clear();
dataGridView2.Rows.Clear();
//if (get == false) //in case when i need to apply condition which I dont prefer
{
string _sql = "select DISTINCT P_batchno,P_sh from PRO where P_name='" + comboProname.Text + "'";
if (comboBthNo.Text != "")
_sql += " AND P_batchno='" + comboBthNo.Text + "' ";
if (SampleToggle)
_sql += " AND IsSample='true' ";
else
_sql += " AND IsSample='false' ";
DataTable dt = DataBase.getDataTable(_sql);
foreach (DataRow dr in dt.Rows)
{
if (comboBthNo.Text == "")
{
dataGridView3.Visible = true;
int i = 0;
dataGridView3.Rows.Insert(i);
dataGridView3.Rows[i].Cells[0].Value = dr["P_batchno"].ToString();
dataGridView3.Focus();
}
sh = dr["P_sh"].ToString();
}
}
//else if (get == true) // opnstk
{
string _sql = "select DISTINCT P_batchno,P_sh from OPN_STK where P_name='" + comboProname.Text + "'";
if (comboBthNo.Text != "")
_sql += " AND P_batchno='" + comboBthNo.Text + "' ";
if (SampleToggle)
_sql += " AND IsSample='true' ";
else
_sql += " AND IsSample='false' ";
DataTable dt = DataBase.getDataTable(_sql);
foreach (DataRow dr in dt.Rows)
{
if (comboBthNo.Text == "")
{
dataGridView3.Visible = true;
int i = 0;
dataGridView3.Rows.Insert(i);
dataGridView3.Rows[i].Cells[0].Value = dr["P_batchno"].ToString();
dataGridView3.Focus();
}
sh = dr["P_sh"].ToString();
}
}
getdata();
}
private void comboBthNo_TextChanged(object sender, EventArgs e)
{
dataGridView3.Rows.Clear();
dataGridView2.Rows.Clear();
// if (get == false)
{
string _sql = "SELECT DISTINCT P_name,P_pack,P_comp,P_expdate,P_rate,P_mrp from PRO where P_batchno='" + comboBthNo.Text + "'";
if (comboProname.Text != "")
_sql += " AND P_name='" + comboProname.Text + "'";
if (SampleToggle)
_sql += " AND IsSample='true' ";
else
_sql += " AND IsSample='false' ";
DataTable dt = DataBase.getDataTable(_sql);
foreach (DataRow dr in dt.Rows)
{
if (comboProname.Text == "")
{
dataGridView2.Visible = true;
int i = 0;
dataGridView2.Rows.Insert(i);
dataGridView2.Rows[i].Cells[0].Value = dr["P_name"].ToString();
dataGridView2.Focus();
}
tbMrp.Text = (dr["P_mrp"].ToString());
dateTimePicker2.Text = (dr["P_expdate"].ToString());
}
}
// else if (get == true) ///// opn stk ///////
{
string _sql = "SELECT DISTINCT P_name,P_pack,P_comp,P_expdate,P_rate,P_mrp from OPN_STK where P_batchno='" + comboBthNo.Text + "'";
if (comboProname.Text != "")
_sql += " AND P_name='" + comboProname.Text + "'";
if (SampleToggle)
_sql += " AND IsSample='true' ";
else
_sql += " AND IsSample='false' ";
DataTable dt = DataBase.getDataTable(_sql);
foreach (DataRow dr in dt.Rows) // I get exception here only on dt
{
if (comboProname.Text == "")
{
dataGridView2.Visible = true;
int i = 0;
dataGridView2.Rows.Insert(i);
dataGridView2.Rows[i].Cells[0].Value = dr["P_name"].ToString();
dataGridView2.Focus();
}
tbMrp.Text = (dr["P_mrp"].ToString());
dateTimePicker2.Text = (dr["P_expdate"].ToString());
}
}
getdata();
}
i would appriciate any help ,thanks in advance .
Put a breakpoint in your code, debug and check that OPN_STK is not null. If it is null that would be your problem.

Sending changes from multiple tables in disconnected dataset to SQLServer

We have a third party application that accept calls using an XML RPC mechanism for calling stored procs.
We send a ZIP-compressed dataset containing multiple tables with a bunch of update/delete/insert using this mechanism. On the other end, a CLR sproc decompress the data and gets the dataset.
Then, the following code gets executed:
using (var conn = new SqlConnection("context connection=true"))
{
if (conn.State == ConnectionState.Closed)
conn.Open();
try
{
foreach (DataTable table in ds.Tables)
{
string columnList = "";
for (int i = 0; i < table.Columns.Count; i++)
{
if (i == 0)
columnList = table.Columns[0].ColumnName;
else
columnList += "," + table.Columns[i].ColumnName;
}
var da = new SqlDataAdapter("SELECT " + columnList + " FROM " + table.TableName, conn);
var builder = new SqlCommandBuilder(da);
builder.ConflictOption = ConflictOption.OverwriteChanges;
da.RowUpdating += onUpdatingRow;
da.Update(ds, table.TableName);
}
}
catch (....)
{
.....
}
}
Here's the event handler for the RowUpdating event:
public static void onUpdatingRow(object sender, SqlRowUpdatingEventArgs e)
{
if ((e.StatementType == StatementType.Update) && (e.Command == null))
{
e.Command = CreateUpdateCommand(e.Row, sender as SqlDataAdapter);
e.Status = UpdateStatus.Continue;
}
}
and the CreateUpdateCommand method:
private static SqlCommand CreateUpdateCommand(DataRow row, SqlDataAdapter da)
{
string whereClause = "";
string setClause = "";
SqlConnection conn = da.SelectCommand.Connection;
for (int i = 0; i < row.Table.Columns.Count; i++)
{
char quoted;
if ((row.Table.Columns[i].DataType == Type.GetType("System.String")) ||
(row.Table.Columns[i].DataType == Type.GetType("System.DateTime")))
quoted = '\'';
else
quoted = ' ';
string val = row[i].ToString();
if (row.Table.Columns[i].DataType == Type.GetType("System.Boolean"))
val = (bool)row[i] ? "1" : "0";
bool isPrimaryKey = false;
for (int j = 0; j < row.Table.PrimaryKey.Length; j++)
{
if (row.Table.PrimaryKey[j].ColumnName == row.Table.Columns[i].ColumnName)
{
if (whereClause != "")
whereClause += " AND ";
if (row[i] == DBNull.Value)
whereClause += row.Table.Columns[i].ColumnName + "=NULL";
else
whereClause += row.Table.Columns[i].ColumnName + "=" + quoted +
val + quoted;
isPrimaryKey = true;
break;
}
}
/* Only values for column that is not a primary key can be modified */
if (!isPrimaryKey)
{
if (setClause != "")
setClause += ", ";
if (row[i] == DBNull.Value)
setClause += row.Table.Columns[i].ColumnName + "=NULL";
else
setClause += row.Table.Columns[i].ColumnName + "=" + quoted +
val + quoted;
}
}
return new SqlCommand("UPDATE " + row.Table.TableName + " SET " + setClause + " WHERE " + whereClause, conn);
}
However, this is really slow when we have a lot of records.
Is there a way to optimize this or an entirely different way to send lots of udpate/delete on several tables? I would really much like to use TSQL for this but can't figure a way to send a dataset to a regular sproc.
Additional notes:
We cannot directly access the SQLServer database.
We tried without compression and it was slower.
If you're using SQL Server 2008, you should look into MERGE
Look here for more info on MERGE

Categories