Not understanding LINQ query - c#

I am maintaining a project and have come across some code which I can't understand. LINQ query:
var toDraw = from tile in testArr.AsEnumerable()
where tile.Item_Business_Unit != null ?
((tile.Ending_Date >= DateTime.Now || tile.Ending_Date == DateTime.MinValue) &&
((tile.Sales_Code == null) || (tile.Sales_Code.ToString() == customerNumber) ||
(tile.Sales_Code.ToString() == cpg)) && (tile.Unit_Price != 0)) :
((tile.Ending_Date >= DateTime.Now || tile.Ending_Date == DateTime.MinValue) &&
((tile.Sales_Code == null) || (tile.Sales_Code.ToString() == customerNumber) ||
(tile.Sales_Code.ToString() == cpg)) && (tile.Unit_Price != 0))
select tile;
From what I understand, from an array a tile is being selected which has the following criteria:
Ending date can be datetime.now or datetime.minvalue
Sales code can be null or can be equal to customer no or cpg
Unit price should be greater than 0
But I am not understanding why there is a conditional expression after tile.Item_Business_Unit since both of the conditions perform the same thing. So will the item be selected even if it has a null business unit? And does this work different from normal if/else operations?
Any suggestions would be very appreciated.

Are you being thrown by the shortcut notation?
x = (test_case) ? (true_part) : (false_part);
If test_case evaluates to true, you would have
Whereas if test_case evaluates to false, this expression would be evaluated
UPDATE:
As an FYI: The resulting test of both sides of that conditional expression above are equal, so that cryptic code is not even necessary.
You could replace that with this:
var toDraw = from tile in testArr.AsEnumerable()
where
((tile.Ending_Date >= DateTime.Now || tile.Ending_Date == DateTime.MinValue) &&
((tile.Sales_Code == null) || (tile.Sales_Code.ToString() == customerNumber) || (tile.Sales_Code.ToString() == cpg)) &&
(tile.Unit_Price != 0))
select tile;

Related

c# linq question about multiple where clauses

I am trying to query a database with multiple where clauses.
IQueryable<string> statusQuery = from m in _context.Flight
where m.Aircraft_Type == aircraftType
&& m.Identification_Registration == registration
&& m.Destination_Airport_City == to1
&& m.DepartureDate.ToString("yyyy-MM-dd") == date1
&& m.Origin_Airport_City == from1
orderby m.Status_Text
select m.Status_Text;
This code is working, but only if I am able to supply a value to each variable.
How can I use this with a check if e.g registration == null => do not check use
&& m.Identification_Registration == registration
if(...) doesn't work here.
You can emulate this behavior using logical operators:
IQueryable<string> statusQuery =
from m in _context.Flight
where m.Aircraft_Type == aircraftType
&& (registration == null || m.Identification_Registration == registration)
&& m.Destination_Airport_City == to1
&& m.DepartureDate.ToString("yyyy-MM-dd") == date1
&& m.Origin_Airport_City == from1
orderby m.Status_Text
select m.Status_Text;

I want to write LINQ where some condition may be null or not

I want to retrieve some data from database based on some condition, for this I'm using LINQ. But problem is that I don't know how to write LINQ when some condition may be null.
from x in _db.AirWorkOrder
join c in _db.Clients on x.ClientId equals c.Id
where x.CreatedOn >= model.StartDate && x.CreatedOn <= model.EndDate && x.ClientId == model.ClientId && x.Type == model.Type && x.WorkOrderStatus == model.Status
select new DateWisedReportItemModel
I want if the clientID, type, status have null value then it will take all the values saved in the DB. and if there are some values provided in it, then it will work according to the condition.
I presume you're asking how to wildcard things that are null. You need to make the particular clause true if your model value is null. You could do this by saying things like:
(dbcolumn == modelvalue || modelvalue == null) && ...
Or like
(dbcolumn == modelvalue == null ? dbvalue : modelvalue) && ...
Or like
(dbcolumn == modelvalue ?? dbvalue)
For example:
from x in _db.AirWorkOrder
join c in _db.Clients on x.ClientId equals c.Id
where
(x.CreatedOn >= model.StartDate ?? x.CreatedOn) &&
(x.CreatedOn <= model.EndDate == null ? x.CreatedOn : model.EndDate) &&
(x.ClientId == model.ClientId || model.ClientId == null) &&
...
I prefer the first as it is the most easy to understand. Also note carefully that it is the only one that will return the row if the row value in the db is null, because to a database null is never equal to null
I want if there is no condition given in ClientId, type and status then only date(this is mandatory) filter will apply, and if there is condition in these only then these(clientId, type and status) conditions will work
It might be most simple, in terms of code readability to do like:
var baseQuery = from x in _db.AirWorkOrder
join c in _db.Clients on x.ClientId equals c.Id
IEnumerable<...> result;
if(model.ClientId == null && model.Type == null && model.Status == null){
//search on date only
result = baseQuery.Where(x.CreatedOn >= model.StartDate && x.CreatedOn <= model.EndDate);
} else {
//search on no null client/type/status only
result = baseQuery.Where(x =>
(x.ClientId == model.ClientId || model.ClientId == null) &&
(x.Type == model.Type || model.Type == null) &&
(x.WorkOrderStatus == model.Status || model.Status == null);
}

Ternary condition in c# logic not working as desired

I have written a ternary condition in c# which isnt evaluating correctly. I am checking if both condition satisfy then it should return true otherwise false. At the moment it is returning true even if one condition fails. So even if the docType is Flashnotes is true, the canView is setting to true. Consider this IoC.Resolve().Authorize("Put", "ManageDocuments")
always returning true and docType may or may not return true
doc.canView = IoC.Resolve<IClientAuthorizationService>().Authorize("Put", "ManageDocuments") ==
AuthAccessLevel.Full && i.DOCUMENT_TYPE_ID != (int) DocumentType.FlashNotes ||
i.DOCUMENT_TYPE_ID != (int)DocumentType.CallMeetingNotes ||
i.DOCUMENT_TYPE_ID != (int)DocumentType.OtherNotes ||
i.DOCUMENT_TYPE_ID != (int)DocumentType.TearSheet
? true
: false;
If I've understood this correctly one of the i.DOCUMENT_TYPE_ID consditions must equate to true? Add parenthesis to equate that first.
doc.canView = IoC.Resolve<IClientAuthorizationService>().Authorize("Put", "ManageDocuments") ==
AuthAccessLevel.Full && (i.DOCUMENT_TYPE_ID == (int) DocumentType.FlashNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.CallMeetingNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.OtherNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.TearSheet)
Also there's no need for the true or false as it's already a bool.
I think what you're trying to do can be simplified into something like this:
var rejectedTypes = new[] { DocumentType.FlashNotes, DocumentType.CallMeetingNotes,
DocumentType.OtherNotes, DocumentType.TearSheet }.Cast<int>();
var accessLevel = IoC.Resolve<IClientAuthorizationService>()
.Authorize("Put", "ManageDocuments");
doc.canView = ((accessLevel == AuthAccessLevel.Full) &&
!rejectedTypes.Contains(i.DOCUMENT_TYPE_ID));
I think there's a mistake in the logic here. Try:
doc.canView = IoC.Resolve<IClientAuthorizationService>().Authorize("Put", "ManageDocuments") ==
AuthAccessLevel.Full && !(i.DOCUMENT_TYPE_ID == (int) DocumentType.FlashNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.CallMeetingNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.OtherNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.TearSheet);
It's an order of operations problem. You can find out more about ordering it here:
doc.canView = IoC.Resolve<IClientAuthorizationService>().Authorize("Put", "ManageDocuments") ==
AuthAccessLevel.Full && (i.DOCUMENT_TYPE_ID != (int) DocumentType.FlashNotes &&
i.DOCUMENT_TYPE_ID != (int)DocumentType.CallMeetingNotes &&
i.DOCUMENT_TYPE_ID != (int)DocumentType.OtherNotes &&
i.DOCUMENT_TYPE_ID != (int)DocumentType.TearSheet)
? true // Redundant code but included to show ternary operator
: false;

Entity Framework Search functionality with Dynamic SQL WHERE clause

hi guys i was using Dynamic SQL for search queries where i used to attach WHERE & AND clause piece by piece and form a statement, i recently came to below alternate for this, and life was amazing
cool alternates of Dynamic WHERE-Clause
Select * From tblEmployees
where EmployeeName = Coalesce(#EmployeeName, EmployeeName) AND
Department = Coalesce(#Department, Department ) AND
Designation = Coalesce(#Designation, Designation) AND
JoiningDate >= Coalesce(#StartDate, JoiningDate) AND
JoiningDate <= Coalesce(#EndDate, JoiningDate) AND
Salary >= Coalesce(#Salary, Salary)
now the issue is since i implemented entity framework i need to achieve same with Linq queries. i have nullable Byte type and nullable boolean which i am currently unable to handle
just like Coalesce my stupid attempt was
&& (s.Floors == deal.Floors.HasValue ? null : s.Floors)
below code not matching any results
[HttpPost]
public ActionResult Results(Deal deal, bool exactMatch)
{
List<Deal> deals;
if (exactMatch)
{
deals = dataBase.Deals.Where(s =>
(s.OwnerName.Contains(deal.OwnerName) || s.OwnerName == null)
&& (s.Rooms == deal.Rooms || s.Rooms == null)
&& (s.BathRooms == deal.BathRooms || s.BathRooms == null)
&& (s.Floors == deal.Floors || s.Floors == null)
&& (s.Builtin == deal.Builtin || s.Builtin == null)
&& (s.Kitchens == deal.Kitchens || s.Kitchens == null)
&& (s.DoubleUnit == deal.DoubleUnit || s.DoubleUnit == null)
&& (s.Corner == deal.Corner || s.Corner == null)
&& (s.Remarks.Contains(deal.Remarks) || s.Remarks == null)
).ToList();
}
else
{
deals = dataBase.Deals.Where(s =>
(s.OwnerName.Contains(deal.OwnerName) || s.OwnerName == null)
|| (s.Rooms == deal.Rooms || s.Rooms == null)
|| (s.BathRooms == deal.BathRooms || s.BathRooms == null)
|| (s.Floors == deal.Floors || s.Floors == null)
|| (s.Builtin == deal.Builtin || s.Builtin == null)
|| (s.Kitchens == deal.Kitchens || s.Kitchens == null)
|| (s.DoubleUnit == deal.DoubleUnit || s.DoubleUnit == null)
|| (s.Corner == deal.Corner || s.Corner == null)
|| (s.Remarks.Contains(deal.Remarks) || s.Remarks == null)
).ToList();
}
return View(deals);
}
table has values like
id Bathroom Floors
1 1 2
2 1 4
3 2 6
4 3 1
i need results which has id 1 & 2
for instance in front end user want to only fill bathroom field with "1" and leave floor field empty
Not really the same. In your query your coalesce is on the parameter then taking the record value as the default if it is null. In your c# lambda you are checking if the parameter is the same as the table value and then checking if the table value is null but that omits the possibility of having a null value in the parameter.
Example
Sql
Department = Coalesce(#Department, Department )
would be
(s.Department == deal.Department || deal.Department == null)
not this which is what you have now
(s.Department == deal.Department || s.Department == null)
Edit
If you wanted to duplicate the COALESCE expression you have now you could write it this way although I am not sure if it would decrease efficiency / performance.
(s.Department == (deal.Department ?? s.Department))
You are testing whether the field in the table equals the 'deal' property or the field is null rather than doing this:
s.Remarks.Contains(deal.Remarks) || deal.Remarks == null
If you do this, it should be the equivalent query.
You can do this cumulatively too. For example with the exact match case you can do:
deals = dataBase.Deals;
if (deal.OwnerName != null)
deals = deals.Where(s => s.OwnerName.Contains(deal.OwnerName));
if (deal.Rooms != null)
deals = deals.Where(s => s.Rooms == deal.Rooms)
That can make the resulting query more efficient. There's a similar way to do this with the non exact match through using unions. I don't know the syntax off hand.

LINQ to entity Error: "Unable to create a null constant value of type ''System.Int32[]". Only entity types, enumeration types

I am receiving the error listed when executing a linq query on my RosterSummaryData_Subject_Local entity. I cannot seem to figure out what is wrong or a solution.
Unable to create a null constant value of type 'System.Int32[]'. Only
entity types, enumeration types or primitive types are supported in
this context.
My LINQ query on my code first entity context:
var subjLocal = customerContext.RosterSummaryData_Subject_Local.Where(s =>
(s.fkRosterSetID == 0) &&
(statsInfo.TestInstanceIDsList.Contains(s.fkTestInstanceID)) &&
(s.fkTestTypeID == statsInfo.TestTypeID) &&
(statsInfo.SchoolYearIDsList.Contains(s.fkSchoolYearID)) &&
(s.fkRosterTypeID == 1) &&
(s.fkSchoolID == 0) &&
(s.fkDepartmentID == 1) &&
(s.fkCourseID == 1) &&
(s.fkPeriodID == 1) &&
(statsInfo.DemoCatIDsList.Contains(s.fkDemoCommonCategoryID)) &&
(statsInfo.DemoCodeIDsList.Contains(s.fkDemoCommonCodeID)) &&
(statsInfo.TestSubjectIDsList.Contains(s.fkTest_SubjectID)));
It sounds like one of your Int32[] types is null. Try adding a check for that before accessing the .Contains methods:
var subjLocal = customerContext.RosterSummaryData_Subject_Local.Where(s =>
(s.fkRosterSetID == 0) &&
(statsInfo.TestInstanceIDsList != null &&
statsInfo.TestInstanceIDsList.Contains(s.fkTestInstanceID)) &&
(s.fkTestTypeID == statsInfo.TestTypeID) &&
(statsInfo.SchoolYearIDsList != null &&
statsInfo.SchoolYearIDsList.Contains(s.fkSchoolYearID)) &&
(s.fkRosterTypeID == 1) &&
(s.fkSchoolID == 0) &&
(s.fkDepartmentID == 1) &&
(s.fkCourseID == 1) &&
(s.fkPeriodID == 1) &&
(statsInfo.DemoCatIDsList != null &&
statsInfo.DemoCatIDsList.Contains(s.fkDemoCommonCategoryID)) &&
(statsInfo.DemoCodeIDsList != null &&
statsInfo.DemoCodeIDsList.Contains(s.fkDemoCommonCodeID)) &&
(statsInfo.TestSubjectIDsList != null &&
statsInfo.TestSubjectIDsList.Contains(s.fkTest_SubjectID)));
Alternatively, if it is Ok for them to be null (I assume it isn't, but just in case), you can change the above checks to follow this pattern:
(statsInfo.DemoCatIDsList == null ||
statsInfo.DemoCatIDsList.Contains(s.fkDemoCommonCategoryID)) &&

Categories

Resources