I have a simple database and I'm trying to make it searchable with multiple criteria. What I do not know is how to get the datagridview to filter using these various criteria all together. I'm doing it very messily I know with the if else statements. If I filter with the combobox, it will disregard all my other criteria. Here's my basic code:
if (StartDate < EndDate)
{
employeeSuggestionsBindingSource.Filter = string.Format("[Suggestion Date] >= #{0:M/dd/yyyy}# AND [Suggestion Date] <= #{1:M/dd/yyyy}#", StartDate, EndDate);
}
else if (string.IsNullOrEmpty(SearchEmp) == false)
{
employeeSuggestionsBindingSource.Filter = string.Format("Employee like '%{0}%'", SearchEmp.Trim().Replace("'", "''"));
}
else if (string.IsNullOrEmpty(SearchSupv) == false)
{
employeeSuggestionsBindingSource.Filter = string.Format("[Supervisor] like '%{0 }%'", SearchSupv.Trim().Replace("'", "''"));
}
else if (string.IsNullOrEmpty(SearchAssigned) == false)
{
employeeSuggestionsBindingSource.Filter = string.Format("[Assigned To] like '%{0}%'", SearchAssigned.Trim().Replace("'", "''"));
}
else if (comboBoxCompleted.Text == "Incomplete")
{
employeeSuggestionsBindingSource.Filter = string.Format("[Completed]='False'");
}
else if (comboBoxCompleted.Text == "Completed")
{
employeeSuggestionsBindingSource.Filter = string.Format("[Completed]='True'");
}
There has to be a much easier way to filter the results and I know I'm probably doing it in the worst way...ha.
If I understand you correctly, you want to build up your filter criteria with one or more predicates. You can do this by composing multiple conditions together with AND:
string filter = null;
if (StartDate < EndDate)
{
filter = CombineCriteria(
filter,
string.Format(
"[Suggestion Date] >= #{0:M/dd/yyyy}# AND " +
"[Suggestion Date] <= #{1:M/dd/yyyy}#",
StartDate,
EndDate));
}
if (string.IsNullOrEmpty(SearchEmp) == false)
{
filter = CombineCriteria(
filter,
string.Format(
"[Employee] LIKE '%{0}%'",
SearchEmp.Trim().Replace("'", "''")));
}
// ... more filter conditions ...
if (comboBoxCompleted.Text == "Incomplete")
filter = CombineCriteria(filter, "[Completed] = False");
else if (comboBoxCompleted.Text == "Completed")
filter = CombineCriteria(filter, "[Completed] = True");
employeeSuggestionsBindingSource.Filter = filter;
Where CombineCriteria() is as follows:
private static string CombineCriteria(string oldCondition, string newCondition) {
if (string.IsNullOrEmpty(oldCondition))
return newCondition;
return "(" + oldCondition+ ") AND (" + newCondition + ")";
}
Related
I am using below query
DataRow[] oFilteredRows =
oTrgFTPTrigList.Select($"ftpPath='{oSrcRow["ftpPath"]}'
and ftpUserName='{oSrcRow["ftpUserName"]}'");
But it fails since ftpPath is url ftp://testURL/
I need to filter and get records with same data as of source (Comparing target and source DataBases)
Here is the answer.
I have converted data like below.
string ftpPath = Uri.EscapeUriString(oSrcRow["ftpPath"].ToString());
Here is the full code sample.
public DataTable compareFTPTriggers(string targetConnectionString)
{
DataTable oFTPTriggerTableDiffs = new DataTable("oFTPTriggerDiffs");
oFTPTriggerTableDiffs.Columns.Add("oFTPTriggerID");
oFTPTriggerTableDiffs.Columns.Add("oFTPTriggerName");
oFTPTriggerTableDiffs.Columns.Add("Comments");
try
{
deFTPTrigger oSrcFTPTrigger = new deFTPTrigger(m_connectString, m_externalUserID);
DataTable oSrcFTPTrigList = oSrcFTPTrigger.getAllFTPTriggers();
string systemUserID = clsSettings.systemUserID(targetConnectionString);
deFTPTrigger oTrgFTPTrigger = new deFTPTrigger(targetConnectionString, systemUserID);
DataTable oTrgFTPTrigList = oTrgFTPTrigger.getAllFTPTriggers();
foreach (DataRow oSrcRow in oSrcFTPTrigList.Rows)
{
string ftpPath = Uri.EscapeUriString(oSrcRow["ftpPath"].ToString());
DataRow[] oFilteredRows = oTrgFTPTrigList.Select($"ftpPath= '{ftpPath}' and ftpUserName='{oSrcRow["ftpUserName"]}'");
string sKey = $"{oSrcRow["ftpPath"]} - {oSrcRow["ftpUserName"]}";
if (oFilteredRows.Length == 0)
{
oFTPTriggerTableDiffs.Rows.Add(oSrcRow["ftpTriggerID"], sKey, "Addition");
}
else
{
if (
oSrcRow["ftpPassword"].ToString() != oFilteredRows[0]["ftpPassword"].ToString() ||
oSrcRow["waitTime"].ToString() != oFilteredRows[0]["waitTime"].ToString() || oSrcRow["waitType"].ToString() != oFilteredRows[0]["waitType"].ToString() ||
oSrcRow["definitionID"].ToString() != oFilteredRows[0]["definitionID"].ToString() || oSrcRow["variableName"].ToString() != oFilteredRows[0]["variableName"].ToString() ||
oSrcRow["enabled"].ToString() != oFilteredRows[0]["enabled"].ToString() || oSrcRow["globalName"].ToString() != oFilteredRows[0]["globalName"].ToString()
)
{
oFTPTriggerTableDiffs.Rows.Add(oSrcRow["ftpTriggerID"], sKey, "Properties are different");
}
}
}
}
catch (Exception ex)
{
// m_oErrorProvider.writeError(ex.Message);
}
DataView dvSorted = oFTPTriggerTableDiffs.DefaultView;
dvSorted.Sort = "oFTPTriggerName ASC";
oFTPTriggerTableDiffs = dvSorted.ToTable();
return (oFTPTriggerTableDiffs);
}
I have a data entry form where user will input DateFrom and DateTo fields.
Select From Date: <input type="text" id="datepickerfrom" name="datepickerfrom"/>
Select To Date: <input type="text" id="datepickerto" name="datepickerto"/>
<asp:Button ID="btnGetData" runat="server" OnClick="BtnGetData_Click" Text="Get Error List" />
I want to build a Linq query that retrieves only top 100 records in case if no input provided.
If user provides DateFrom and does not provide DateTo, the user will select data which is greater than DateFrom up to DateTime.Now.
If user provides DateTo and does not provide DateFrom, the user will select data which is less then DateTo.
I have the following now:
public static List<ErrorLogData> GetLogErrorData(string appName, InputData data)
{
SqlConnection con;
List<ErrorLogData> errorLogData = null;
string query = "";
if (data.DateFrom == "" && data.DateTo == "")
{
query += "from ld in logData.errorLogs.Take(10000)";
}
if (data.DateFrom == "" && data.DateTo != "")
{
query += "from ld in logData.errorLogs where ld.errorTime <= " + data.DateTo;
}
if (data.DateFrom != "" && data.DateTo == "")
{
query += "from ld in logData.errorLogs where ld.errorTime >= " + data.DateFrom + " && <= " + DateTime.Now;
}
if (data.DateFrom != "" && data.DateTo != "")
{
query += "from ld in logData.errorLogs where ld.errorTime >= " + data.DateFrom + " && <= " + data.DateTo;
}
DateTime dateFrom = Convert.ToDateTime(data.DateFrom);
DateTime dateTo = Convert.ToDateTime(data.DateTo);
using (con = new SqlConnection(ConfigurationManager.AppSettings[conKey]))
using (WebEntities logData = new WebEntities())
{
logData.CommandTimeout = 300;
var errorLog = query +
select new ErrorLogData
{
ErrorID = ld.errorID,
ErrorTime = ld.errorTime,
UserName = ld.username,
ErrorType = ld.errorType,
Error = ld.error,
ControlNumber = ld.controlNumber
};
errorLogData = errorLog.ToList();
}
return errorLogData;
}
I'm not sure how to append query to "select new ErrorLogData..." statement to have the entire query.
What is the approach here?
You should just be able to use the IQueryable result of error log, and then perform lambda expressions for your if statements.
List<ErrorLogData> errorLogData = null;
DateTime dateFrom = Convert.ToDateTime(data.DateFrom);
DateTime dateTo = Convert.ToDateTime(data.DateTo);
//IQueryable errorLog
var errorLog = from ld in logData.errorLogs
select new ErrorLogData
{
ErrorID = ld.errorID,
ErrorTime = ld.errorTime,
UserName = ld.username,
ErrorType = ld.errorType,
Error = ld.error,
ControlNumber = ld.controlNumber
};
if (data.DateFrom == "" && data.DateTo == "")
{
errorLogData = errorLog.Take(10000);
}
if (data.DateFrom == "" && data.DateTo != "")
{
errorLogData = errorLog.where(x => x.ErrorTime <= dateTo).ToList();
//query += "from ld in logData.errorLogs where ld.errorTime <= " + data.DateTo;
}
//contine to implement If
return errorLogData;
Assuming that you are using some kind of LINQ data access technology, use something like the following:
private List<Entity> GetData(DateTime? dateFrom, DateTime? dateTo)
{
IQueryable<Entity> query = ...; //Here reference your table
if (dateFrom == null && dateTo == null)
{
query = query.Take(100);
}
else
{
DateTime dateToValue = dateTo ?? DateTime.Now;
query = query.Where(x => x.Date <= dateToValue);
if (dateFrom != null)
{
query = query.Where(x => x.Date >= dateFrom.Value);
}
}
return query.ToList(); //This will actually execute the query. Here you can expand your query to select specific columns before executing ToList
}
I have a method to apply some dynamic ordering to an IQueryable. Here is the relevant code:
if (orderBy != 0)
{
if (thenBy != 0 && thenBy != orderBy)
{
results = results.OrderBy(request.OrderBy + " ASC, " + request.ThenBy + " ASC");
}
else if (thenByDesc != 0 && thenByDesc != orderBy)
{
results = results.OrderBy(request.OrderBy + " ASC, " + request.ThenByDesc + " DESC");
}
else
{
results = results.OrderBy(request.OrderBy + " ASC");
}
}
The problem is the ordering doesn't seem to be working correctly. By example, ordering by the property "Name" which is just a string, doesn't even seem to work.
A fix I did find was to toList() the results before applying the ordering, like so:
orderedResults = results.ToList().AsQueryable();
and then do the OrderBy on the orderedResults variable. This would be fine but the results that I am ordering can potentially contain 1000's of items. The performance in this case is quite bad. Is there another solution without bringing the collection into memory?
UPDATE
In hindsight, the code I posted isn't clear. Here is the entire method:
public static IOrderedQueryable<TSource> Order<TSource, TOrdering>(this IQueryable<TSource> results, RequestBase<TOrdering> request)
{
var genericType = typeof(TOrdering);
if (!genericType.IsEnum) return (IOrderedQueryable<TSource>)results;
var orderBy = Convert.ToInt32(request.OrderBy as Enum);
var orderByDesc = Convert.ToInt32(request.OrderByDesc as Enum);
var thenBy = Convert.ToInt32(request.ThenBy as Enum);
var thenByDesc = Convert.ToInt32(request.ThenByDesc as Enum);
if (orderBy != 0)
{
if (thenBy != 0 && thenBy != orderBy)
{
results = results.OrderBy(request.OrderBy + " ASC, " + request.ThenBy + " ASC");
}
else if (thenByDesc != 0 && thenByDesc != orderBy)
{
results = results.OrderBy(request.OrderBy + " ASC, " + request.ThenByDesc + " DESC");
}
else
{
results = results.OrderBy(request.OrderBy + " ASC");
}
}
else if (orderByDesc != 0)
{
if (thenBy != 0 && thenBy != orderByDesc)
{
results = results.OrderBy(request.OrderByDesc + " DESC, " + request.ThenBy + " ASC");
}
else if (thenByDesc != 0 && thenByDesc != orderByDesc)
{
results = results.OrderBy(request.OrderByDesc + " DESC, " + request.ThenByDesc + " DESC");
}
else
{
results = results.OrderBy(request.OrderByDesc + " DESC");
}
}
return (IOrderedQueryable<TSource>)results;
}
request.OrderBy and the other ordering properties are enums. This enum can have values such as 'Name', 'SubmittedDate', etc. on which to order results by. This is how I call the method:
reportsResponses = reportsResponses.Order(request);
UPDATE 2
Further information about the code. I mentioned that the ordering works if I first do this before applying any ordering:
results = results.ToList().AsQueryable();
Prior to this, the results are calculated from a mongo driver. We're obtaining the results by querying a mongodb. Is mongo the weak link here?
Following is the UI :
And this is code snippet i am using to fire dynamic where clause :
public void bind()
{
string filter = "";
if (!string.IsNullOrEmpty(txtPart.Text))
{
filter = filter + "masterinv.inv_item_id = " + txtPart.Text;
}
if (!string.IsNullOrEmpty(txtDescription.Text))
{
if (!string.IsNullOrEmpty(filter))
{
filter = filter + " || masterinv.description = " + txtDescription.Text;
}
else
{
filter = filter + "masterinv.description = " + txtDescription.Text;
}
}
if (!string.IsNullOrEmpty(txtVendor.Text))
{
if (!string.IsNullOrEmpty(filter))
{
filter = filter + " || vendor.vendor_name = " + txtVendor.Text;
}
else
{
filter = filter + "vendor.vendor_name = " + txtVendor.Text;
}
}
InventoryDataContext dc = new InventoryDataContext(InventoryDBContext.GetConnectionstring());
var searchResult = (from masterinv in dc.OMS_REF_Master_Inventories
join vendor in dc.OMS_REF_Vendors on masterinv.inv_item_id equals vendor.inv_item_id
Where(filter)
select new OMS_REF_Master_Inventory
{
inv_item_id = masterinv.inv_item_id,
description = masterinv.description,
unit_of_measure = masterinv.unit_of_measure,
lot_id = masterinv.lot_id,
serial_id = masterinv.serial_id,
mfg_id = masterinv.mfg_id,
mfg_item_id = masterinv.mfg_item_id,
item_status_current = masterinv.item_status_current,
cm_unit_cost = masterinv.cm_unit_cost,
sync_dte = masterinv.sync_dte
}).ToList();
searchResult;
}
In the above code filter created on the basis of combination of combo box and text field
selection.
Out of these one filter is :
masterinv.inv_item_id = 'A' || masterinv.description = 'F' || vendor.vendor_name = 'V'
it may vary depend upon the combobox value selection. All cases of Combo box present in BuildQueryFilter Method.
PROBLEM :
I am not able to fire where clause in this join. Where i am going wrong ?
I think you cannot use those % with linq queries.
Instead of % you can use Contains()/StartsWith()/EndsWith()
refer this for more info...
How to do SQL Like % in Linq?
How to do a LIKE query with linq?
Or
Use Sql Methods..
where SqlMethods.Like(c.CustomerName, "%/abc/%")
I am accessing a database with c#. Now I have to make some calculations with data that I get from some tables and write it into other existing tables. This works quite good in most cases, but for complex operations it takes a huge amount of time. Now I want to know what would be good practice to speed up my querys and get to my results. Here is what I do:
I get a data table that contains 3 values (lom(unique id), laktanfang, laktende) that contains about 700 rows.
For each row in this table I do a query from another table. This results in another data table containing 2 values (lom(unique id), behanddatum)
Now I check if the the value of behanddatum is in between laktanfang and laktende --> yes: Add the row to the data table that gets returned by my function --> no: go on
In the end I have to get the number of positive results from my data table
Here is the code I currently use. I hope it's not too confusing.
public DataTable HoleAbgeschlosseneLaktationenMitDiagnosen(DateTime daAnfang, DateTime daEnde, string[] stDiagnosen = null)
{
DataTable dtRet = new DataTable();
dtRet.Columns.Add("lom", typeof(string));
dtRet.Columns.Add("laktanfang", typeof(DateTime));
dtRet.Columns.Add("laktende", typeof(DateTime));
DataTable dtAbgänge = HoleAbgängeVonEinzeltierZugang(daEnde, daAnfang);
//Abgeschlossene Laktationen für abgegegangene Tiere
foreach (DataRow dr in dtAbgänge.Rows)
{
if (dr != null)
{
DateTime daAbgangsdatum = dr.Field<DateTime>("abgangsdatum");
string stLom = dr.Field<string>("lom");
DataTable dtKalbungVorAbgang = HoleLetzteKalbungFuerTier(stLom, daAbgangsdatum);
if (dtKalbungVorAbgang.Rows.Count > 0 && !dtKalbungVorAbgang.Rows[0].IsNull("kalbedatum"))
{
DateTime daKalbedatum = (DateTime)dtKalbungVorAbgang.Rows[0]["kalbedatum"];
int inLaktation = (int)dtKalbungVorAbgang.Rows[0]["laktation"];
if (PrüfeObDiagnoseInZeitraumAufgetreten(stLom, stDiagnosen, daKalbedatum, daAbgangsdatum) || stDiagnosen == null)
{
DataRow drLaktAbgang = dtRet.NewRow();
drLaktAbgang["lom"] = stLom;
drLaktAbgang["laktanfang"] = daKalbedatum;
drLaktAbgang["laktende"] = daAbgangsdatum;
dtRet.Rows.Add(drLaktAbgang);
}
if (daKalbedatum >= daAnfang && inLaktation > 1)
{
DataTable dtVorherigeKalbung = HoleLetzteKalbungFuerTier(stLom, daKalbedatum.AddDays(-1));
DateTime daVorhKalbung = (DateTime)dtVorherigeKalbung.Rows[0]["kalbedatum"];
if (dtVorherigeKalbung.Rows.Count > 0 && !dtVorherigeKalbung.Rows[0].IsNull("kalbedatum"))
{
if (PrüfeObDiagnoseInZeitraumAufgetreten(stLom, stDiagnosen, daKalbedatum, daAbgangsdatum) || stDiagnosen == null)
{
DataRow drLaktVorhKalbung = dtRet.NewRow();
drLaktVorhKalbung["lom"] = stLom;
drLaktVorhKalbung["laktanfang"] = daVorhKalbung;
drLaktVorhKalbung["laktende"] = daKalbedatum;
dtRet.Rows.Add(drLaktVorhKalbung);
}
}
}
}
}
}
DataTable dtKalbungen = HoleKalbungenFürLebendTiere(daEnde, daAnfang);
//Abgeschlossene Laktationen für lebende Tiere
foreach (DataRow dr in dtKalbungen.Rows)
{
DateTime daKalbedatumLetzte = dr.Field<DateTime>("kalbedatum");
string stLom = dr.Field<string>("lom");
int inLaktation = dr.Field<int>("laktation");
if (inLaktation > 1)
{
DataTable dtKalbungVorErster = HoleLetzteKalbungFuerTier(stLom, daKalbedatumLetzte.AddDays(-1));
if (!dtKalbungVorErster.Rows[0].IsNull("kalbedatum"))
{
DateTime daKalbedatum = (DateTime)dtKalbungVorErster.Rows[0]["kalbedatum"];
if (PrüfeObDiagnoseInZeitraumAufgetreten(stLom, stDiagnosen, daKalbedatum, daKalbedatumLetzte) || stDiagnosen == null)
{
DataRow drLaktKalbung = dtRet.NewRow();
drLaktKalbung["lom"] = stLom;
drLaktKalbung["laktanfang"] = daKalbedatum;
drLaktKalbung["laktende"] = daKalbedatumLetzte;
dtRet.Rows.Add(drLaktKalbung);
}
inLaktation = (int)dtKalbungVorErster.Rows[0]["laktation"];
if (daKalbedatum >= daAnfang && inLaktation > 1)
{
DataTable dtVorherigeKalbung = HoleLetzteKalbungFuerTier(stLom, daKalbedatum.AddDays(-1));
if (dtVorherigeKalbung.Rows.Count > 0 && !dtVorherigeKalbung.Rows[0].IsNull("kalbedatum"))
{
DateTime daVorhKalbung = (DateTime)dtVorherigeKalbung.Rows[0]["kalbedatum"];
if (PrüfeObDiagnoseInZeitraumAufgetreten(stLom, stDiagnosen, daVorhKalbung, daKalbedatum) || stDiagnosen == null)
{
DataRow drLaktVorhKalbung = dtRet.NewRow();
drLaktVorhKalbung["lom"] = stLom;
drLaktVorhKalbung["laktanfang"] = daVorhKalbung;
drLaktVorhKalbung["laktende"] = daKalbedatum;
dtRet.Rows.Add(drLaktVorhKalbung);
}
}
}
}
}
}
return dtRet;
}
private bool PrüfeObDiagnoseInZeitraumAufgetreten(string stLom, string[] stDiagnosen, DateTime daAnfang, DateTime daEnde)
{
SqlCommand cmd = new SqlCommand();
DataTable dtDiagnosenGefunden = new DataTable();
cmd.CommandText = "SELECT diagnose " +
"FROM b_milch_hms_diagnose " +
"WHERE lom=#lom AND behanddatum >= #datumanfang AND behanddatum <= #datumende";
if (stDiagnosen != null)
{
int i = 0;
foreach (string st in stDiagnosen)
{
if (st != "")
{
if (i == 0)
cmd.CommandText += " AND diagnose LIKE #gesuchte_diagnose" + i;
else
cmd.CommandText += " OR diagnose LIKE #gesuchte_diagnose" + i;
cmd.Parameters.AddWithValue("#gesuchte_diagnose" + i, st + "%");
}
i++;
}
}
cmd.Parameters.AddWithValue("#lom", stLom);
cmd.Parameters.AddWithValue("#datumanfang", daAnfang);
cmd.Parameters.AddWithValue("#datumende", daEnde);
dtDiagnosenGefunden = w_milch.FühreSqlAus(cmd);
if (dtDiagnosenGefunden.Rows.Count > 0 && !dtDiagnosenGefunden.Rows[0].IsNull("diagnose"))
return true;
return false;
}
I hope you can help me to improve this function to work more efficient or at least give me some hints.
Thanks in advance
You have created a N+1 problem. One way to solve this would be to change HoleAbgängeVonEinzeltierZugang so that it joins in the data you need from the b_milch_hms_diagnose table.
If you are using .NET 4.0, you can also try to use parallel foreach and see the impact it has on the loop execution time. (This is a more general advice you could apply to many examples)
_dtAbgänge.Rows.AsParallel().ForEach(dr=>
{
//do work
});