Using ternary operation without else in linq? - c#

I need to know how do i use ternary operator without else. In the example I need to check 2 criterias (cityId != null) && (cityId != 0). I cannot use normal if conditions. So if it doesn't happen i want to list all titles. I don't want to show else condition is x.ProvinceId == 15
public JsonResult mt(int? cityId)
{
var getCities = locationRepository.Get(null).Where(x => ( (cityId != null) && (cityId != 0) ? x.ProvinceId == cityId : x.ProvinceId == 15 )).Select(x=>x.Title);
return Json(new { items = getCities }, JsonRequestBehavior.AllowGet);
}

The conditional operator is a ternary operator, meaning it accepts three operands. So omitting one is like omitting the second operand of an addition.
However you can simply reformat it as one condition
Depending on what should actually happen if the condition is not met.
This will accept all that does not meet the condition you have
x => (cityId ?? 0) == 0 || x.ProvinceId == cityId

Related

LINQ query needed using a conditional operand in the WHERE clause

I am having trouble composing a LINQ statement that uses a conditional operand within the where clause and have looked through this site for a similar problem without any luck. I'm sure there is a better way to express this query. The value XXX within the is the result of determining which field in the object to use for comparison and is explained below.
Below is what I am trying to accomplish:
var paymentReceivedAmt = (from registerEntry in RegisterEntries
where registerEntry.TransactionType != null
&& registerEntry.TransactionType.Id.SubsystemCode == "A"
&& registerEntry.Receipt != null
&& registerEntry.PostDate != null
&& XXX >= lastInvoicedDate
select registerEntry.TransactionAmount.GetValueOrDefault(0)).Sum();
Value XXX =
if registerEntry.AddedDate = registerEntry.PostDate
registerEntry.AddedDate
else
registerEntry.PostDate
The values registerEntry.AddedDate and registerEntry.PostDate are DateTime type, however when comparing I need to only compare the date and not the time
Does anyone have any idea on how to do this?
Why not just use registerEntry.PostDate for XXX? If it is equal to registerEntry.AddedDate, might as well use it and simplify the whole thing
var paymentReceivedAmt = (from registerEntry in RegisterEntries
where registerEntry.TransactionType != null
&& registerEntry.TransactionType.Id.SubsystemCode == "A"
&& registerEntry.Receipt != null
&& registerEntry.PostDate != null
&& registerEntry.PostDate >= lastInvoicedDate
select registerEntry.TransactionAmount.GetValueOrDefault(0)).Sum();
Depending on the LINQ provider you're using you can try the ternary operator:
var paymentReceivedAmt = (from registerEntry in RegisterEntries
where registerEntry.TransactionType != null
&& registerEntry.TransactionType.Id.SubsystemCode == "A"
&& registerEntry.Receipt != null
&& registerEntry.PostDate != null
&& (registerEntry.AddedDate == registerEntry.PostDate
? registerEntry.AddedDate
: registerEntry.PostDate) >= lastInvoicedDate
select registerEntry.TransactionAmount.GetValueOrDefault(0)).Sum();

Null value in linq where clause

I'm having an issue where I want to return results where something matches and I get an error if one of the properties I'm trying to match is null.
if (!string.IsNullOrEmpty(searchString))
{
Infos = Infos.Where(
x =>
x.FirstName.ToLower().Contains(searchString) ||
x.LastName.ToLower().Contains(searchString) ||
x.ContractNum.ToLower().Contains(searchString) ||
x.VIN.ToLower().Contains(searchString) ||
x.Claim.InitiatedBy.ToLower().Contains(searchString)
).ToList();
}
If ContractNum or VIN, for example, are null then it throws an error. I'm not sure how to check if one of these are null inside of a linq query.
You can add explicit null checks:
Infos = Infos.Where(
x =>
(x.FirstName != null && x.FirstName.ToLower().Contains(searchString)) ||
(x.LastName != null && x.LastName.ToLower().Contains(searchString)) ||
(x.ContractNum != null && x.ContractNum.ToLower().Contains(searchString)) ||
(x.VIN != null && x.VIN.ToLower().Contains(searchString)) ||
(x.Claim != null && x.Claim.InitiatedBy != null && x.Claim.InitiatedBy.ToLower().Contains(searchString))
).ToList();
You have multiple options, first is to do an explicit check against null and the other option is to use Null propagation operator.
x.FirstName != null && x.FirstName.ToLower().Contains(searchString)
or
x.FirstName?.ToLower()?.Contains(searchString) == true
But I would suggest you to use IndexOf instead of Contains for case
insensitive comparison.
something like:
x.FirstName?.IndexOf(searchString, StringComparison.CurrentCultureIgnoreCase) >= 0)
Checking the property is null or empty before comparing it it's the only way I know
if (!string.IsNullOrEmpty(searchString))
{
Infos = Infos.Where(
x =>
(!String.IsNullOrEmpty(x.FirstName) && x.FirstName.ToLowerInvariant().Contains(searchString)) ||
(!String.IsNullOrEmpty(x.LastName) && x.LastName.ToLowerInvariant().Contains(searchString)) ||
(!String.IsNullOrEmpty(x.ContractNum) && x.ContractNum.ToLowerInvariant().Contains(searchString)) ||
(!String.IsNullOrEmpty(x.VIN) && x.VIN.ToLowerInvariant().Contains(searchString)) ||
(x.Claim != null && !String.IsNullOrEmpty(x.Claim.InitiatedBy) && x.Claim.InitiatedBy.ToLowerInvariant().Contains(searchString))
).ToList();
}
EXTRA: I added a check on the Claim property to make sure it's not null when looking at InitiatedBy
EXTRA 2: Using the build in function IsNullOrEmpty to compare string to "" and nullso the code is clearer.
Extra 3: Used of ToLowerInvariant (https://msdn.microsoft.com/en-us/library/system.string.tolowerinvariant(v=vs.110).aspx) so the lowering action will act the same no matter of the culture.
You could use ?? to replace it with a acceptable value.
(x.ContractNum??"").ToLower()
I would use the null conditional operator ?, this will however, return a nullable bool? so you will need to handle that appropriately.
Some examples on how to do this:
x?.FirstName?.ToLower().Contains(searchString) == true;
x?.FirstName?.ToLower().Contains(searchString) ?? false;
An alternative method to keep the comparison logic in one place to use a sub collection of the properties and check on those:
Infos = Infos.Where(i=>
new[] {i.FirstName,i.LastName,i.ContractNum /*etc*/}
.Any(w=> w?.ToLower().Contains(searchString) ?? false))
.ToList();
(It does read out all properties, but that shouldn't cost much performance and gains much maintainability )

Use ?: Operand on entity framework

I want to use it in this way
Context.Moves.OfType<Cuotes>().Where(p =>
p.Final == true
&& dtFrom.DateTime != null ? p.DeliverDate >= dtFrom.DateTime : true
&& dtTo.DateTime != null ? p.DeliverDate <= dtToHasta.DateTime : true
&& !ckShowDelivered.Checked ? p.Delivered == false : true
&& !ckShowDelivered.Checked ? p.Canceled == false : true
);
Due I have muliple filters I tried to manipulate in this way, actually I have another checkbox to condition if old Cuotes versions are showed with Final == false statement, but this operand inside the Where clause seems to be not working.
It is a way to apply this operand or I must to hard code the if conditions for each combination of options posible?
You could just chain those in separate Where calls:
var result = Context.Moves.OfType<Cuotes>().Where(p => p.Final == true);
if (dtFrom.DateTime != null)
result = result.Where(p => p.DeliverDate >= dtFrom.DateTime);
if (dtTo.DateTime != null)
result = result.Where(p => p.DeliverDate <= dtToHasta.DateTime);
if (!ckShowDelivered.Checked)
result = result.Where(p => !p.Delivered);
if (!ckShowDelivered.Checked)
result = result.Where(p => !p.Canceled);
That way, you can use any kind of external conditions to affect your query without having to use those external conditions within the query itself.

Coalesce in Linq

I'm trying to get the cashassignment_id column if the column doesn't have data then print 0 as result. But the Cash 1 is Missing.
Cash_DataTable data:
cash_id cash_name
1 cash 1
2 cash 2
3 cash 3
CashAssignments_DataTable data:
cashassignment_id cash_id cashassignment_valid
100 1 0 (false)
200 1 0 (false)
300 1 0 (false)
My current linq result:
cash_id cashassignment_id cash_name
2 0 cash 2
3 0 cash 3
Note: Cash 1 is missing, I need to show all the cash when cashassignment_valid = true else return 0 as cashassignment_id
DataTable CashStatusProc1 = new DataTable();
CashStatusProc1.Columns.Add("cash_id", typeof(Int32));
CashStatusProc1.Columns.Add("cashassignment_id", typeof(Int32));
CashStatusProc1.Columns.Add("cash_name", typeof(String));
(from Cash in Cash_DataTable.AsEnumerable()
join CashAssignments in CashAssignments_DataTable.AsEnumerable()
on Cash.Field<Int32>("cash_id") equals CashAssignments.Field<Int32>("cash_id")
into JoinedCashAssignments
from CashAssignments in JoinedCashAssignments.DefaultIfEmpty()
where ((((CashAssignments != null ? CashAssignments.Field<Boolean>("cashassignment_valid") : false) == true) || (CashAssignments == null)) )
select new
{
cash_id = Cash.Field<Int32>("cash_id"),
cashassignment_id = (CashAssignments != null ? CashAssignments.Field<Int32>("cashassignment_id") : 0),
cash_name = Cash.Field<String>("cash_name")
}).Aggregate(CashStatusProc1, (dt, result) =>
{
dt.Rows.Add(result.cash_id, result.cashassignment_id, result.cash_name); return dt;
});
This might not really be an answer but it might lead you in the right direction and take care of a bug or two, lets go through your code alittle.
In the where statement there are several conundrums.
((((CashAssignments != null ? CashAssignments.Field<Boolean>("cashassignment_valid") : false) == true) || (CashAssignments == null)) )
First lets clean it. (flipped the != to ==)
(CashAssignments == null ? false :
CashAssignments.Field<Boolean>("cashassignment_valid")) == true
|| CashAssignments == null
Now lets look at it, you're asking if the CashAssignments is equal to null and if it is then you return false and the you check is CashAssignments equal to false then return true. this kindof means the same as
if (x == null || x != null) //Will always happen
also the (CashAssignments == null ? false : CashAssignments.Field<Boolean>("cashassignment_valid")) == true is somewhat redundant and equals to
bool z;
if(CashAssignments == null) z = false;
else z = CashAssignments.Field<Boolean>("cashassignment_valid")
if(z == true) // This is redundant just do the work in the else
so drop the || CashAssignments == null from it and handle it on the first expression
(CashAssignments == null ? true :
CashAssignments.Field<Boolean>("cashassignment_valid"))
actually we can go further. what you have can be seen as
x == null ? true : x.value //x.value might be true or false
// Equal to
if(x == null || x.value)
so we can write it like this (even tinyer and more readable)
CashAssignments == null ||
CashAssignments.Field<Boolean>("cashassignment_valid")
so what you are in essence asking for is if CashAssignments is null or if CashAssignments.Field<Boolean>("cashassignment_valid") is true do work
Next is the select expression
cash_id = Cash.Field<Int32>("cash_id"),
cashassignment_id = (CashAssignments != null ? CashAssignments.Field<Int32>("cashassignment_id") : 0),
cash_name = Cash.Field<String>("cash_name")
only one thing of interest here the cashassignment_id and its mostly cleanup for readability ( the flip on != to == is mostly my own taste)
cashassignment_id = CashAssignments == null ? 0 :
CashAssignments.Field<Int32>("cashassignment_id")
Rest more or less looks good. By disectiong your code im assuming the error lays in the where statement and might have been resorted by the cleanup and redundancy removal as they overlapped in several areas.
Other things to note:
In the statement you declare as i see it CashAssignments twice, once as the result of the join and once more as the result of default if empty.
Also since you floor it to default, instead of null that you could test against default(DataTable) as a safety measure in-case the default is not null (for alot of cases it is null, one example is the default of int that is 0 and not null and 0 == null equals to false

more short code about if statement

i wanted to try the following code:
//all arrays are List<T> type.
if (m.terms[0] != null && m.terms[0].labels != null && m.terms[0].labels[0].title == "Part-of-speech")
{
result = true;
}
but it occured runtime error occasionly in following situation
i. m.terms == null
ii. m.terms != null, but m.terms[0] does not intialized.
iii. m.terms != null, and m.terms[0] has been exist but
m.terms[0].label does not initialized.
...
so i did modify it to like this:
if (m.terms[0] != null)
{
if (m.terms[0].labels != null)
{
if (m.terms[0].labels[0].title == "Part-of-speech") { result = true; }
}
}
is it the best way?
&& is a short circuiting operator, so the first way you wrote it and the second way will be functionally equivalent.
if (a && b && c)
{
// work
}
b will only be evaluated if a returns true. (Same goes for c).
In your code, checking m.terms[0].labels will not be a problem because you would have short-circuited out of the expression if m.terms[0] had been null.
To completely cover yourself, you'd want to possibly add checks for m and m.terms, however.
m != null && m.terms != null && m.terms.Count > 0 && m.terms[0] != null ...
As it evaluates from left to right, it will break on the first condition that doesn't pass and the rest will go unchecked.
int index = 0;
int labelIndex = 0;
string titleToCheck = "Part-of-speech";
if (m != null && m.terms != null && m.terms.Count > index)// or m.Length...
{
if (m.terms[index] != null && m.terms[index].labels != null &&
m.terms[index].labels.Count > labelIndex)
{
if (m.terms[index].labels[labelIndex].title == titleToCheck)
{
result = true;
}
}
}
This is all about readability. C# uses Short-circuit evaluation so in functionality there is no difference.
try this
if (m!=null && m.terms!= null && m.terms[0].labels!=null && m.terms[0].labels[0].title!=null && m.terms[0].labels[0].title == "Part-of-speech")
Yes, it would be better to split off each null check into a separate if statement.
The reason is that the second and third conditions require the first to not be null. If the first is null, then the second and third conditions will in turn throw errors because their parent is null yet is trying to be accessed.

Categories

Resources