I write this query but the result from it is wrong
var query = from item in db.Advances
where CurrentConfiguration.currentLanguage == GeneralDefinitions.arabicSymbol
? item.eUser.name.ToLower().Contains(strSearchKey)
: item.eUser.englishName.ToLower().Contains(strSearchKey)
&& !item.isPaid
&& item.expectedPaymentMonth == dExpectedPayment.Month
&& item.expectedPaymentYear == dExpectedPayment.Year
&& item.advanceTypeId == (int)enumAdvanceType.AtOnce
select item;
The wrong is in
item.expectedPaymentMonth == dExpectedPayment.Month
&& item.expectedPaymentYear == dExpectedPayment.Year
It is always true although item.expectedPaymentMonth != dExpectedPayment.Month
Is there any syntax error or something wrong in this query ?
Try this:
var query =
from item in db.Advances
where (CurrentConfiguration.currentLanguage
== GeneralDefinitions.arabicSymbol
? item.eUser.name
: item.eUser.englishName).ToLower().Contains(strSearchKey)
where !item.isPaid
where item.expectedPaymentMonth == dExpectedPayment.Month
where item.expectedPaymentYear == dExpectedPayment.Year
where item.advanceTypeId == (int)enumAdvanceType.AtOnce
select item;
I suspect that the ternary operator is causing you grief.
You must group booleans because of ?: expression! See:
var query = from item in db.Advances
where
(
CurrentConfiguration.currentLanguage == GeneralDefinitions.arabicSymbol
? item.eUser.name.ToLower().Contains(strSearchKey)
: item.eUser.englishName.ToLower().Contains(strSearchKey)
)
&& !item.isPaid
&& item.expectedPaymentMonth == dExpectedPayment.Month
&& item.expectedPaymentYear == dExpectedPayment.Year
&& item.advanceTypeId == (int)enumAdvanceType.AtOnce
select item;
If you don't use (), all expressions after item.eUser.englishName.ToLower().Contains(strSearchKey) will be AND with item.eUser.englishName.ToLower().Contains(strSearchKey) and finally returns a single result!
ALSO you can use separate where clauses:
var query = from item in db.Advances
where
CurrentConfiguration.currentLanguage == GeneralDefinitions.arabicSymbol
? item.eUser.name.ToLower().Contains(strSearchKey)
: item.eUser.englishName.ToLower().Contains(strSearchKey)
where !item.isPaid
&& item.expectedPaymentMonth == dExpectedPayment.Month
&& item.expectedPaymentYear == dExpectedPayment.Year
&& item.advanceTypeId == (int)enumAdvanceType.AtOnce
select item;
Perhaps because the ? operator is not between () and you are testing arabicSymbol ?
try: (extra lines added for clarity)
where
(
CurrentConfiguration.currentLanguage == GeneralDefinitions.arabicSymbol ? item.eUser.name.ToLower ().Contains(strSearchKey) : item.eUser.englishName.ToLower().Contains(strSearchKey)
)
&& !item.isPaid && item.expectedPaymentMonth == dExpectedPayment.Month && item.expectedPaymentYear == dExpectedPayment.Year
&& item.advanceTypeId == (int)enumAdvanceType.AtOnce
select item;
Both answers above are correct as they relate to operator prescedence (http://msdn.microsoft.com/en-us/library/aa691323(v=vs.71).aspx)
The && is evaluated before the ?:. Therefore you're effectively seeing all the &&'s being applied the the else portion of the ?: expression.
Related
I have below LINQ query:
SailingMain_Details = SailingMain_Details.Where(f => f.Duration == durationCr_Filter
&& f.DeparturePortID == depPortCr_Filter
&& f.CruiseLine == cruLineCr_Filter
&& f.ShipName == cruShipCr_Filter
&& f.DestinationCr == destinationCr_Filter).ToList();
in above query sometime i get some parameters values like value=="any". in that situation i want to avoid checking only that parameter. Can anyone please guide me how to do that. Thanks.
The below might work if you want to skip the condition if the filter is "any"
SailingMain_Details =
SailingMain_Details.Where(f => (durationCr_Filter != "any" ? f.Duration == durationCr_Filter : true)
&& (depPortCr_Filter != "any" ? f.DeparturePortID == depPortCr_Filter : true)
&& (cruShipCr_Filter != "any" ? f.ShipName == cruShipCr_Filter : true)
&& (cruLineCr_Filter != "any" ? f.CruiseLine == cruLineCr_Filter : true)
&& (destinationCr_Filter != "any" ? f.DestinationCr == destinationCr_Filter : true)).ToList();
To achieve what you want let me show you by example with DeparturePortID. Let's say "any" valu eis -1:
SailingMain_Details = SailingMain_Details
.Where(f =>
f.Duration == durationCr_Filter
&& (depPortCr_Filter == -1 || f.DeparturePortID == depPortCr_Filter)
&& f.CruiseLine == cruLineCr_Filter
&& f.ShipName == cruShipCr_Filter
&& f.DestinationCr == destinationCr_Filter)
.ToList();
Here, if depPortCr_Filter is -1, then (depPortCr_Filter == -1 || f.DeparturePortID == depPortCr_Filter) evaluates to true, independently of f.DeparturePortID == depPortCr_Filter condition.
Apply every filter on separate. example
if(durationCr_Filter.toUpper() != "ANY")
SailingMain_Details = SailingMain_Details.Where(f => f.Duration == durationCr_Filter);
if(depPortCr_Filter.toUpper() != "ANY")
SailingMain_Details = SailingMain_Details.Where(f => f.DeparturePortID == depPortCr_Filter);
if(cruLineCr_Filter.toUpper() != "ANY")
SailingMain_Details = SailingMain_Details.Where(f => f.CruiseLine == cruLineCr_Filter);
if(cruShipCr_Filter.toUpper() != "ANY")
SailingMain_Details = SailingMain_Details.Where(f => f.ShipName == cruShipCr_Filter);
if(destinationCr_Filter.toUpper() != "ANY")
SailingMain_Details = SailingMain_Details.Where(f => f.DestinationCr == destinationCr_Filter);
I assume here some parameter means it can be for any of those 5 params so you can try something like
SailingMain_Details = SailingMain_Details.Where(f => (f.Duration == durationCr_Filter || durationCr_Filter == "any")
&& (f.DeparturePortID == depPortCr_Filter || depPortCr_Filter == "any") &&
(f.CruiseLine == cruLineCr_Filter || cruLineCr_Filter == "any") && (f.ShipName == cruShipCr_Filter || cruShipCr_Filter == "any") &&
(f.DestinationCr == destinationCr_Filter || destinationCr_Filter == "any") ).ToList();
You can do it like
if (SailingMain_Details.Any(x => x.value == "any"))
{
// avoid the check here
SailingMain_Details = SailingMain_Details.Where(f => f.Duration == durationCr_Filter && f.DeparturePortID == depPortCr_Filter && f.CruiseLine == cruLineCr_Filter && f.ShipName == cruShipCr_Filter && f.DestinationCr == destinationCr_Filter).ToList();
}
else
{
SailingMain_Details = SailingMain_Details.Where(f => f.Duration == durationCr_Filter && f.DeparturePortID == depPortCr_Filter && f.CruiseLine == cruLineCr_Filter && f.ShipName == cruShipCr_Filter && f.DestinationCr == destinationCr_Filter).ToList();
}
e.g avoid checking means basically it shall return true by default. for one item see below. other can follow the same
&& (depPortCr_Filter == 'any' || f.DeparturePortID == depPortCr_Filter).
I have a query
return uow.CustomerRepo
.Get()
.Where
(
c=>
c.Firstname.StartsWith(customerSearch.Initial) &&
c.Surname == customerSearch.Surname &&
c.Email == customerSearch.Email &&
c.Postcode == customerSearch.PostCode
)
Is there a way to skip parts of the query if something in customerSearch is empty?
so I want to skip the part
c.Surname == customerSearch.Surname
if
customerSearch.Surname
Is empty
You can do it with a condition that checks the customerSearch part explicitly:
.Where
(
c=>
(customerSearch.Initial == null || c.Firstname.StartsWith(customerSearch.Initial)) &&
(customerSearch.Surname == null || c.Surname == customerSearch.Surname) &&
(customerSearch.Email == null || c.Email == customerSearch.Email) &&
(customerSearch.PostCode == null || c.Postcode == customerSearch.PostCode)
)
If you need to check for empty strings rather than null, change the condition accordingly.
I have a filter called serviceEntryFilter with a property System which could have values for instance EP1, EP2 OR EP1 and sometimes this filter would be null. If there are multiple values or a single value then the query (IN) clause runs fine . If the filter value is null then I get the following error:
Unable to create a constant value of type 'System.String[]'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
[HttpPost]
public ActionResult List(string ServiceEntryStatus, string ServiceEntryReconciled, string ServiceEntryReliabilityRecord, string ActiveServiceEntry,
int PageNo, ServiceEntryFilter serviceEntryFilter = null)
{
string[] systems = null;
var list = (from se in db.ServiceEntry
join r in db.RunLogEntry on se.RunLogEntryID equals r.ID into joinRunLogEntry
from r2 in joinRunLogEntry.DefaultIfEmpty()
join u in db.User on se.TechnicianID equals u.ID
join s in db.System1 on se.SystemID equals s.ID
where (
((se.RunLogEntryID == 0 || se.RunLogEntryID != null))
&& ((serviceEntryFilter.ID.HasValue == false) || (se.ID == serviceEntryFilter.ID.Value && serviceEntryFilter.ID.HasValue == true))
&& ((serviceEntryFilter.ServiceDateTime.HasValue == false) || (EntityFunctions.TruncateTime(se.ServiceDateTime) == EntityFunctions.TruncateTime(serviceEntryFilter.ServiceDateTime) && serviceEntryFilter.ServiceDateTime.HasValue == true))
&& ((serviceEntryFilter.RunDate.HasValue == false) || (EntityFunctions.TruncateTime(r2.RunDate) == EntityFunctions.TruncateTime(serviceEntryFilter.RunDate) && serviceEntryFilter.RunDate.HasValue == true))
&& ((serviceEntryFilter.Technician == null) || (u.FullName.Contains(serviceEntryFilter.Technician.Trim()) && serviceEntryFilter.Technician != null))
&& (
((ServiceEntryStatus == "O" && se.ServiceRequestClosed == false) ||
(ServiceEntryStatus == "C" && se.ServiceRequestClosed == true) ||
(ServiceEntryStatus == "A")
)
)
&& (
((ServiceEntryReliabilityRecord == null) ||
(ServiceEntryReliabilityRecord == "N" && se.ReliabilityRecord == false) ||
(ServiceEntryReliabilityRecord == "Y" && se.ReliabilityRecord == true) ||
(ServiceEntryReliabilityRecord == "A")
)
)
&& (
((ServiceEntryReconciled == null) ||
(ServiceEntryReconciled == "N" && se.Reconciled == false) ||
(ServiceEntryReconciled == "Y" && se.Reconciled == true) ||
(ServiceEntryReconciled == "A")
)
)
&& (
((ActiveServiceEntry == null) ||
(ActiveServiceEntry == "N" && se.Active == false) ||
(ActiveServiceEntry == "Y" && se.Active == true) ||
(ActiveServiceEntry == "A")
)
)
&& (
(s.PlatformID == platformID) || (platformID == 0)
)
&& ((serviceEntryFilter.System == null) || ((serviceEntryFilter.System != null) && systems.Contains(s.SystemFullName)))
)
orderby se.ID descending
select new ServiceSearchEntry()
{
ID = se.ID,
ServiceDateTime = se.ServiceDateTime,
Technician = u.FullName,
System = s.SystemFullName,
ReasonForFailure = se.ReasonForFailure,
RunDate = (r2 == null ? (DateTime?)null : r2.RunDate)
});
var listData = list.Skip((page - 1) * PageSize).Take(PageSize);
ServiceEntriesListViewModel viewModel = new ServiceEntriesListViewModel()
{
ServiceSearchEntry = listData,
PagingInfo = new PagingInfo
{
CurrentPage = page,
ItemsPerPage = PageSize,
TotalItems = list.Count()
}
};
}
The Issue:
The following clause is throwing an error when SystemFilter.System is NULL. It is null at times when users do not select values for it. Sample values are as follows:
EP1, EP2
EP1
TP2, TP3, TP4
&& ((serviceEntryFilter.System == null) || ((serviceEntryFilter.System != null) && systems.Contains(s.SystemFullName)))
If it has a value, then I put it in an array and its works like a charm, its just when its null.
The issue is that everything inside a LINQ statement will get translated to SQL. There isn't really a conditional statement that I see here that says "don't try to add this array filter if it's actually null".
I would initialize the systems array to a zero length array, overwrite it if the filter.Systems is not null, and then make my linq statement as follows:
systems.Contains(s.SystemFullName)
Don't include that null checking inside the LINQ statement as it's not doing what you are expecting.
To build conditional LINQ statements, you might want to look at PredicateBuilder: http://www.albahari.com/nutshell/predicatebuilder.aspx
This is a known limitation with Linq to Entities - see section on Referencing Non-Scalar Variables Not Supported.
In otherwords, this line:
systems.Contains(s.SystemFullName)
can't be used as part of your EF query.
I have a where clause that looks up child objects on an entity:
var Lookup = row.Offenses.Where(x => x.Desc == co.Desc && x.Action == co.Action && x.AppealYN == co.AppealYN && x.OffDate == co.OffDate).ToList();
Sometimes the co.OffDate can be null, which will cause an exception. Right now, the only way I can think of to get around that, is to use an if statement:
if (co.OffDate.HasValue)
{
var Lookup = row.Offenses.Where(x => x.Desc == co.Desc && x.Action == co.Action && x.AppealYN == co.AppealYN && x.OffDate == co.OffDate).ToList();
}
else
{
var Lookup = row.Offenses.Where(x => x.Desc == co.Desc && x.Action == co.Action && x.AppealYN == co.AppealYN).ToList();
}
Is there anyway I can re-write the linq query to accomplish what the if statement does? I still want to do a lookup, even if the co.OffDate is null.
You could insert a ternary into your Where filter:
var Lookup = row.Offenses
.Where(x =>
x.Desc == co.Desc
&& x.Action == co.Action
&& x.AppealYN == co.AppealYN
&& (co.OffDate.HasValue ? x.OffDate == co.OffDate : true)
).ToList();
I would rewrite it to be more readable (in my opinion):
var query = row.Offenses.Where(x => x.Desc == co.Desc
&& x.Action == co.Action
&& x.AppealYN == co.AppealYN)
if (co.OffenseDate.HasValue)
{
query = query.Where(x.OffDate == co.OffenseDate);
}
var Lookup = query.ToList();
The following works fine:
(from e in db.EnquiryAreas
from w in db.WorkTypes
where
w.HumanId != null &&
w.SeoPriority > 0 &&
e.HumanId != null &&
e.SeoPriority > 0 &&
db.Enquiries.Where(f =>
f.WhereId == e.Id &&
f.WhatId == w.Id &&
f.EnquiryPublished != null &&
f.StatusId != EnquiryMethods.STATUS_INACTIVE &&
f.StatusId != EnquiryMethods.STATUS_REMOVED &&
f.StatusId != EnquiryMethods.STATUS_REJECTED &&
f.StatusId != EnquiryMethods.STATUS_ATTEND
).Any()
select
new
{
EnquiryArea = e,
WorkType = w
});
But:
(from e in db.EnquiryAreas
from w in db.WorkTypes
where
w.HumanId != null &&
w.SeoPriority > 0 &&
e.HumanId != null &&
e.SeoPriority > 0 &&
EnquiryMethods.BlockOnSite(db.Enquiries.Where(f => f.WhereId == e.Id && f.WhatId == w.Id)).Any()
select
new
{
EnquiryArea = e,
WorkType = w
});
+
public static IQueryable<Enquiry> BlockOnSite(IQueryable<Enquiry> linq)
{
return linq.Where(e =>
e.EnquiryPublished != null &&
e.StatusId != STATUS_INACTIVE &&
e.StatusId != STATUS_REMOVED &&
e.StatusId != STATUS_REJECTED &&
e.StatusId != STATUS_ATTEND
);
}
I get the following error:
base {System.SystemException}: {"Method 'System.Linq.IQueryable1[X.Enquiry]
BlockOnSite(System.Linq.IQueryable1[X.Enquiry])' has no supported translation to SQL."}
Linq to Sql only translates certain method calls to SQL, and yours (BlockOnSite) is not one of them. Hence the error. The fact that your method takes an IQueryable<T> and returns an IQueryable<T> doesn't make it special.
Ok I solved it using:
IQueryable<Enquiry> visibleOnSite = EnquiryMethods.VisibleOnSite(db.Enquiries);
var combinations = (from e in db.EnquiryAreas
from w in db.WorkTypes
where
w.HumanId != null &&
w.SeoPriority > 0 &&
e.HumanId != null &&
e.SeoPriority > 0 &&
visibleOnSite.Where(f => f.WhereId == e.Id && f.WhatId == w.Id).Any()
select
new
{
EnquiryArea = e,
WorkType = w
});