I am creating an application in C# MVVM. I have a simple question. Is there any possibility to store math operator in variable? I have a code like that:
public ICollectionView FilteredCollection
{
get
{
return filteredCollection;
}
set
{
filteredCollection = value;
OnPropertyChanged("FilteredCollection");
}
}
FilteredCollection.Filter = x => (
(string.IsNullOrEmpty(DynamicSearchEmployeeName) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeName))
&& (DynamicSearchEmployeeID == null || ((Employee)x).EmployeeID == DynamicSearchEmployeeID)
&& (string.IsNullOrEmpty(DynamicSearchEmployeeSalary) || ((Employee)x).EmployeeSalary == Convert.ToInt32(DynamicSearchEmployeeSalary))
&& (string.IsNullOrEmpty(DynamicSearchEmployeeDesigner) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeDesigner))
&& (string.IsNullOrEmpty(DynamicSearchEmployeeEmailID) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeEmailID))
);
What I want to achieve:
In fourth line (DynamicSearchEmployeeSalary) math operator should be depended on following conditions:
if (IsPressedEqual == true)
VARIABLE = "=="
if (IsPressedLess == true)
VARIABLE = "<"
if (IsPressedGreater == true)
VARIABLE = ">"
if (IsPressedLess == true && IsPressedEqual == true)
VARIABLE = "<="
if (IsPressedGreater == true && IsPressedEqual == true)
VARIABLE = ">="
Scenario:
For example I put a value like 10000 in textbox, then click on button with "=" operator. As a result I want to receive Employees with Salary equals than 10000.
Then I click on ">". And I have Employees with Salary greater and equals 10000.
FilteredCollection.Filter = x => (
(string.IsNullOrEmpty(DynamicSearchEmployeeName) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeName))
&& (DynamicSearchEmployeeID == null || ((Employee)x).EmployeeID == DynamicSearchEmployeeID)
&& (string.IsNullOrEmpty(DynamicSearchEmployeeSalary) || ((Employee)x).EmployeeSalary VARIABLE Convert.ToInt32(DynamicSearchEmployeeSalary))
&& (string.IsNullOrEmpty(DynamicSearchEmployeeDesigner) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeDesigner))
&& (string.IsNullOrEmpty(DynamicSearchEmployeeEmailID) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeEmailID))
I've made a simple Rule Based Engine ... I think it will help you in your issue ...
please find it as a nuget package here: https://www.nuget.org/packages/IbnSherien.RuleBasedEngine/
you can create a rule like this:
var rule = RuleEngine.CreateRule<Employee>()
.If<Employee>(e => e.EmployeeSalary).GreaterThan(DynamicSearchEmployeeSalary)
.Validate();
FilteredCollection.Filter = x => (
(string.IsNullOrEmpty(DynamicSearchEmployeeName) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeName))
&& (DynamicSearchEmployeeID == null || ((Employee)x).EmployeeID == DynamicSearchEmployeeID)
&& (string.IsNullOrEmpty(DynamicSearchEmployeeSalary) || rule.Match((Employee)x).IsMatch)
&& (string.IsNullOrEmpty(DynamicSearchEmployeeDesigner) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeDesigner))
&& (string.IsNullOrEmpty(DynamicSearchEmployeeEmailID) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeEmailID))
feel free to add any comments or contribute to the package
Related
Code
if(Model.CurrentStatus == 1 || Model.CurrentStatus == 2)
{
//can display those records..
}
else if((Model.CurrentStatus == 3 || Model.CurrentStatus == 4) && Model.Date != null)
{
if(Model.Date <= 30 days)
{
//can display those records..
}
}
I have tried the following code and unable to complete it fully as expected
#Html.Partial("Filter", new IndexModel()
{
Id = Model.Id,
Collection = Model.Collection.Where((a => a.CurrentStatus == 1 || a.CurrentStatus == 2)
&& )
})
How to convert the above if condition to linq in cshtml. Thanks
the else-if relationship is an OR relationship. So simply combine the two lines. the inner nested if inside the else if is an AND relationship. This would go into the second set of parentheses
Collection = Model.Collection.Where
(
(a => a.CurrentStatus == 1 || a.CurrentStatus == 2) ||
((a.CurrentStatus == 3 || a.CurrentStatus == 4) && a.Date != null && a.Date <= 30)
)
EDIT:
Here is another suggestion: extract the readable code into an own method that evaluates the condition and returns the boolean result. This way you can make a predicate that can be accepted by the Where method:
private bool IsForDisplay( ModelDataType Model )
{
if(Model.CurrentStatus == 1 || Model.CurrentStatus == 2)
{
//can display those records..
return true;
}
else if((Model.CurrentStatus == 3 || Model.CurrentStatus == 4) && Model.Date != null)
{
if(Model.Date <= 30 days)
{
//can display those records..
return true;
}
}
return false;
}
now you can use it simply in the linq expression:
#Html.Partial("Filter", new IndexModel()
{
Id = Model.Id,
Collection = Model.Collection.Where(a => IsForDisplay(a))
});
I have a large project where I have dozens of linq statements where I am looking for a matching record by checking several fields to see if they match or both field and compared field are null.
var testRecord = new { firstField = "bob", secondField = (string)null, thirdField = "ross" };
var matchRecord = dataContext.RecordsTable.FirstOrDefault(vi =>
(vi.first == testRecord.firstField || ((vi.first == null || vi.first == string.Empty) && testRecord.firstField == null))
&& (vi.second == testRecord.secondField || ((vi.second == null || vi.second == string.Empty) && testRecord.secondField == null))
&& (vi.third == testRecord.thirdField || ((vi.third == null || vi.third == string.Empty) && testRecord.thirdField == null)));
//do stuff with matchRecord
Ideally I would replace all that duplicated code (used around 50 times across the system I'm working on) with something like the following
Expression<Func<string, string, bool>> MatchesOrBothNull = (infoItem, matchItem) => (
infoItem == matchItem || ((infoItem == null || infoItem == string.Empty) && matchItem == null));
var matchRecord = dataContext.RecordsTable.FirstOrDefault(vi =>
MatchesOrBothNull(vi.first, testRecord.firstField)
&& MatchesOrBothNull(vi.second, testRecord.secondField)
&& MatchesOrBothNull(vi.third, testRecord.thirdField));
//do stuff with matchRecord
My question is two-fold: First, is there a matched or both null function already available? (I've looked without luck).
Second, the code block above compiles, but throws a "no supported translation to sql" error, is there a way to have a function in the where clause? I know that there is a translation because it works if I don't pull it into the function. How can I get that translated?
First of all you can check whether string is null or empty with single code which is called : String.IsNullOrEmpty(vi.first). You need a method like this one :
public bool MatchesOrBothNull(string first,string second){
if(first==second||String.IsNullOrEmpty(first)||String.IsNullOrEmpty(second))
return true;
else return false;
}
You can use it in where clause
var matchRecord = dataContext.RecordsTable.Where(vi =>
MatchesOrBothNull(vi.first, testRecord.firstField)
&& MatchesOrBothNull(vi.second, testRecord.secondField)
&& MatchesOrBothNull(vi.third, testRecord.thirdField)
).FirstOrDefault();
I've been working on this for hours today and feel like there is an easy way to do this but I am unable to make it work by anything but brute force.
I have an entity in my application that serves as a Mapping between two objects, based on 5 filters. The goal is to find the record with the most specific match to the filters.
Right now, I am manually brute forcing 2^5 queries to get the most specific row, but feel like there has to be a much easier way to do this.
The only gotcha here is that there may be no match in the database for a specific filter (or all), in which case I want to select the NULL record.
Below I have an excerpt of my embarrassing brute force query -- I first want to try and match on all 5 filters, then on permutations of 4 matching, then 3, then 2, then 1, and finally all Nulls.
incList.FirstOrDefault(x =>
x.Filter1 == filter1Parameter && x.Filter2 == filter2Parameter && x.Filter3 == filter3Parameter && x.Filter4 == filter4Parameter && x.Filter5 == filter5Parameter
|| x.Filter1 == null && x.Filter2 == filter2Parameter && x.Filter3 == filter3Parameter && x.Filter4 == filter4Parameter && x.Filter5 == filter5Parameter
|| x.Filter1 == filter1Parameter && x.Filter2 == null && x.Filter3 == filter3Parameter && x.Filter4 == filter4Parameter && x.Filter5 == filter5Parameter
|| x.Filter1 == filter1Parameter && x.Filter2 == filter2Parameter && x.Filter3 == null && x.Filter4 == filter4Parameter && x.Filter5 == filter5Parameter
|| x.Filter1 == filter1Parameter && x.Filter2 == filter2Parameter && x.Filter3 == filter3Parameter && x.Filter4 == null && x.Filter5 == filter5Parameter
|| x.Filter1 == filter1Parameter && x.Filter2 == filter2Parameter && x.Filter3 == filter3Parameter && x.Filter4 == filter4Parameter && x.Filter5 == null
I originally thought I could have a simple statement that would independently grab the value if present, and grab null if not
incList.FirstOrDefault(x => (x.Filter1 == filter1Parameter || x.Filter1 == null) &&
(x.Filter2 == filter2Parameter || x.Filter2 == null) &&
(x.Filter3 == filter3Parameter || x.Filter3 == null) &&
(x.Filter4 == filter4Parameter || x.Filter4 == null) &&
(x.Filter5 == filter5Parameter || x.Filter5 == null));
But that did not work.
Any pointers would be appreciated.
I'm still trying to understand the full extent of the requirement.
However, have you explored abstracting this Func or Func(s) in a separate class. This separate class or classes would operate like a Strategy. Only in charge of what filters a collection based on a certain predicate.
If that does not seem like a good route, what about looking into writing your own implementation IEqualityComparer. This will allow you determine what makes these objects equal.
You can introduce something like a "fitness function" and then select item with max fit value
var bestMatch = incList.Select(x => new
{
item = x,
fit =
(x.Filter1 == null
? 1
: (x.Filter1 == filter1Parameter ? 2 : 0)) *
(x.Filter2 == null
? 1
: (x.Filter2 == filter2Parameter ? 2 : 0)) // and so on
})
.OrderByDescending(x => x.fit)
.FirstOrDefault(x => x.fit > 0)?.item;
I'm still pretty new to this, so go easy on me. I'm trying to get linq to return a single record when the query returns multiple identical records. Here's what I have:
var query = (from i in _db.BizListView
let dist = DbGeography.FromText(i.Point).Distance(DbGeography.FromText(geog)) * .0006214
where
dist <= rng &&
i.Name.Contains(key) &&
pri != -1 ? (i.BizCategoryID == pri && i.Primary == true) : true &&
biz != -1 ? (i.BizCategoryID == biz) : true
group i by new
{
ClientID = i.ClientID,
Name = i.Name,
Address = i.Address,
Address1 = i.City + ", " + i.StateID + " " + i.PostCode,
BizPhone = i.BizPhone,
EmailAddress = i.EmailAddress,
ClientImagePath = i.ClientImagePath,
Distance = DbGeography.FromText(i.Point).Distance(DbGeography.FromText(geog)) * 0.0006214
}
into myTable
orderby myTable.Key.Distance ascending
select new
{
ClientID = myTable.Key.ClientID,
Name = myTable.Key.Name,
Address = myTable.Key.Address,
Address1 = myTable.Key.Address1,
BizPhone = myTable.Key.BizPhone,
EmailAddress = myTable.Key.EmailAddress,
ClientImagePath = myTable.Key.ClientImagePath,
Distance = myTable.Key.Distance
}).Distinct();
return query;
The query produces a single record for each client, as long as a BizCategory is specified, but returns multiple identical records per client (a record for each of the Client's BizCategories) if no BizCategory is specified. How can I get the query to return a single record per client, instead of multiple identical records when no BizCategory is specified?
I believe that operator precedence is affecting the query.
Try adding parentheses around the ternary operators.
(pri != -1 ? (i.BizCategoryID == pri && i.Primary == true) : true) &&
(biz != -1 ? (i.BizCategoryID == biz) : true)
A simpler way to express this condition could be:
(pri == -1 || i.BizCategoryID == pri) &&
(biz == -1 || i.BizCategoryID == biz)
The way it was interpreted:
pri != -1
? (i.BizCategoryID == pri && i.Primary == true)
: (true && (biz != -1 ? (i.BizCategoryID == biz) : true))
|< ----- IGNORED ----------------------------->|
You can see that the true && biz != -1... took precedence here. As true was evaluated first, the biz was never evaluated.
Gah!! All I had to do was add an additional conditional!
var query = from i in _db.BizListView
let dist = DbGeography.FromText(i.Point).Distance(DbGeography.FromText(geog)) * 0.0006214
where
dist <= rng &&
i.Name.Contains(key) &&
pri != -1 ? (i.BizCategoryID == pri && i.Primary == true) : true &&
biz != -1 ? (i.BizCategoryID == biz) : true &&
(biz == -1 && pri == -1) ? (i.Primary == true): true
orderby i.Distance ascending
select i;
Oh well. Live and learn.
var q = from p in query
where
((criterias.birthday == p.BirthDay|| criterias.birthday == null))
&& ((criterias.marriageDate == null || criterias.marriageDate == p.MarriageDate))
&& ((criterias.gender == p.Gender) || (criterias.gender == null))
&& ((criterias.nationalities.Contains(p.Nationality)) || (criterias.nationalities == null))
criterias isa class where i store my search criterias. nationalities is a string list. the problem occurs when i have no items in string. the query throws null reference exception. the query doesnt accept null value in nationalities. how can i fix this?
Reverse the order so that the null check comes before the query: as you're using ||, the second part of the expression is only evaluated when the first part evaluates to false:
&& ((criterias.nationalities == null) ||
(criterias.nationalities.Contains(p.Nationality)))
Look at these 2:
((criterias.birthday == p.BirthDay|| criterias.birthday == null))
&& ((criterias.marriageDate == null || criterias.marriageDate == p.MarriageDate))
I don't think marriageDate will give you problems but birthday uses the wrong order.
In this case you need the 'short-circuit evaluation' property of ||, change it to:
(criterias.birthday == null || criterias.birthday == p.BirthDay)
&& (criterias.marriageDate == null || criterias.marriageDate == p.MarriageDate)
Try swapping the order of the nationalties checks. It should short-circuit on the null check before it tries to evaluate the Contains.
((criterias.nationalities == null) || (criterias.nationalities.Contains(p.Nationality)))
Turn this statement around:
(criterias.nationalities.Contains(p.Nationality)) || (criterias.nationalities == null)
so that it reads
(criterias.nationalities == null) || (criterias.nationalities.Contains(p.Nationality))
If the first operand evaluates to true, the second one will be skipped.
Try first check for null then (if it is not null) check for contains:
var q = from p in query
where
((criterias.birthday == p.BirthDay|| criterias.birthday == null))
&& ((criterias.marriageDate == null || criterias.marriageDate == p.MarriageDate))
&& ((criterias.gender == p.Gender) || (criterias.gender == null))
&& ((criterias.nationalities == null) || (criterias.nationalities.Contains(p.Nationality))