Linq where clause confusion - c#

Good day, everyone!
I've written one query for my Automation test, but it's taking too long to execute, and I'm not sure how to optimize it effectively because I'm new to the Linq where clause.
Could someone please assist me with this?
var order = OrderRepositoryX.GetOrderByStatus(OrderStatusType.Dispatched, 4000)
.Where(x => x.siteId == 1 || x.siteId == 10 || x.siteId == 8 || x.siteId == 16 || x.siteId == 26 || x.siteId == 27)
.Where(x =>
{
var totalPrice = OrderRepository.GetOrderById(shared_parameters.testConfiguration, x.orderId).TotalPrice;
if (totalPrice < 500)
return false;
return true;
})
.Where(x =>
{
var cnt = ReturnOrderRepositoryX.CheckReturnOrderExists(x.orderId);
if (cnt > 0)
return false;
return true;
})
.Where(x =>
{
var cnt = OrderRepositoryX.CheckActiveOrderJobDetailsByOrderId(x.orderId);
if (cnt > 0)
return false;
return true;
})
.FirstOrDefault();

The biggest code smell here is that you are calling other repositories inside the Where clause which (assuming that repositories actually hit database) it will effectively mean that you are hitting database per every queried item. Lets imagine that OrderRepositoryX.GetOrderByStatus(OrderStatusType.Dispatched, 4000) and first Where will result in 1000 items, only second Whereclause will lead to 1000 queries to the database (and you have some more calls to repositories in subsequent Wheres). And all of this to get just one item (i.e. FirstOrDefault).
Usual approach is to avoid calling database in loops (what Where basically does here) and rewrite such code so only single SQL query will be performed against the database returning only what is needed and performing all the filtering on the database side.

Please try this instead
Avoid too many where clauses. It gets a result and then applies another check on the whole set.
var order = OrderRepositoryX.GetOrderByStatus(OrderStatusType.Dispatched, 4000)
.FirstOrDefault(x => x.siteId == 1 || x.siteId == 10 || x.siteId == 8 || x.siteId == 16 ||
x.siteId == 26 || x.siteId == 27) &&
(x =>
{
var totalPrice = OrderRepository.GetOrderById(shared_parameters.testConfiguration, x.orderId)
.TotalPrice;
return totalPrice >= 500;
})
&& (x =>
{
var cnt = ReturnOrderRepositoryX.CheckReturnOrderExists(x.orderId);
return cnt <= 0;
})
&& (x =>
{
var cnt = OrderRepositoryX.CheckActiveOrderJobDetailsByOrderId(x.orderId);
return cnt <= 0;
});

Related

How to write a linq query to exclude some of the records?

This is my LINQ
IList<string> ExceptList = new List<string>() { "045C388E96", "C9B735E166", "02860EB192", "2401016471" };
var listusers = context.USER_INFO.Where(x => x.ACTIVATED
&& x.COMP.EQUIPMENT.Count(y => y.STATUS == (int)STATUSEQ.ACTIVE) > 0
&& (x.LAST_LOGIN < time)
&& !ExceptList.Contains(x.COMP.CODE)
&& !x.IS_LOCK
|| !x.COMP.IS_LOCK)
.Select(x => new EmailOutOfDateLoginModel
{
COMPCode = x.COMP.CODE,
First_Name = x.FIRST_NAME,
Last_Name = x.LAST_NAME,
Total_EQ = x.COMP.EQUIPMENT.Count(y => y.STATUS == (int)STATUSEQ.ACTIVE),
User_Email = x.USER_EMAIL
}).ToList();
I am not sure why my ExceptList is not working. I want to exclude any record that contaisn any of the CODE in the ExceptList
Put parentheses around the expressions containing the && logic. The || at the end is only matched with the !x.IS_LOCK || !x.COMP.IS_LOCK otherwise.
According your linq all records where (!x.COMP.IS_LOCK==true) will be included in the query. Try this "where" part:
.Where(x => x.ACTIVATED
&& x.COMP.EQUIPMENT.Count(y => y.STATUS == (int)STATUSEQ.ACTIVE) > 0
&& (x.LAST_LOGIN < time)
&& !ExceptList.Contains(x.COMP.CODE)
&& !(x.IS_LOCK && x.COMP.IS_LOCK))

LINQ Query with method syntax

My requirement is to make boolean value (IsPC=true) only if I found any value with IsCurrent = true from the list and second condition is to filter the list with G or W codes and third condition is to check the PCBNumber length ==15 with only one from the list.
How short can i able to reduce the below query using LINQ method syntax
below is my query
var CurrentQ= p.List.Where(x => x.IsConCurrent== true);
if (CurrentQ.Count() > 0)
{
var NCurrentQwithWorQ = p.List.Where(x => x.Codes == Codes.W|| x.Codes== Codes.Q).Count();
if (NCurrentQwithWorQ != null)
{
var PCBNumber = p.List.Where(x => x.PCBNumber .Length == 15).Count();
if (PCBNumber == 1)
{
isPC = true;
}
}
}
You can use all conditions in same query like below,
var PCBNumber= p.List.Where(x => x.IsConCurrent== true && (x.Codes == Codes.W|| x.Codes== Codes.Q) && x.PCBNumber.Length == 15);
if (PCBNumber !=null && PCBNumber.Count() == 1)
{
isPC = true;
}
I'm not trying to debug what you wrote, but isn't this really what you're looking for--that is, daisy-chaining your Where conditions?
var isPC = p.List.Where(x => x.IsConCurrent == true).Where(x => x.Codes == Codes.W || x.Codes == Codes.Q).Where(x => x.PCBNumber.Length == 15).Count() == 1;
Both solutions suggested above are correct.
p.List.Where(x => x.IsConCurrent== true && (x.Codes == Codes.W|| x.Codes== Codes.Q) && x.PCBNumber.Length == 15);
p.List.Where(x => x.IsConCurrent == true).Where(x => x.Codes == Codes.W || x.Codes == Codes.Q).Where(x => x.PCBNumber.Length == 15).Count()
Actually they are performed in the same way. The Where function does not force immediate iteration through the data source. Only when you execute the Count function, LINQ will process row by row and execute criterion by criterion to find out which values should be calculated.
I can only suggest you add the Take(2) operator after the where clause. In this case LINQ will stop after finding the first two rows that matches provided criterion and other rows will not be processed.
p.List.Where(x => x.IsConCurrent == true)
.Where(x => x.Codes == Codes.W || x.Codes == Codes.Q)
.Where(x => x.PCBNumber.Length == 15)
.Take(2).Count()

C# Linq check if value exists

I have a database structured like this:
Detector:
DetectorID SiteID TrackID
1401 1400 2
1402 1400 2
1601 1600 2
1602 1600 2
DetectorStatus:
DetectorStatusID DetectorID DateTime DetectorModeID Status
1 1601 TimeStamp 2 0.86
2 1602 TimeStamp 2 0.84
Now i have a filter which let me see the Detectors based on their DetectorMode.
Code:
var query = loadOperation.Entities; //Define the query
if (ShowAtlas == false && ShowPhoenix == false || ShowAtlas == true && ShowPhoenix == true)
{
if (filterany1.IsChecked == true)
{
query = query.OrderBy(d => d.SiteName);
}
if (filterok1.IsChecked == true)
{
query = query.Where(d => d.Detectors.Count(t => t.DetectorStatus.Count(a => a.DetectorModeID == 2) > 0) > 0);
}
if (filtermaintenance1.IsChecked == true)
{
query = query.Where(d => d.Detectors.Count(t => t.DetectorStatus.Count(a => a.DetectorModeID == 3 || a.DetectorModeID == 4 || a.DetectorModeID == 5) > 0) > 0);
}
if (filternotworking.IsChecked == true)
{
query = query.Where(d => d.Detectors.Count(t => t.DetectorStatus.Count(a => a.DetectorModeID == 6 || a.DetectorModeID == 7) > 0) > 0);
}
}
Now, when a detector is Unknow. It wont be in the DetectorStatus table. As given in the example. DetectorID's 1401 and 1402 are unknown.
When i filter on:
if (filternotworking.IsChecked == true)
{
query = query.Where(d => d.Detectors.Count(t => t.DetectorStatus.Count(a => a.DetectorModeID == 6 || a.DetectorModeID == 7) > 0) > 0);
}
I also want to order on the unknown detector types.
How do i achieve this?
Because right now i count the results. But if there is nothing, it wont show anything.
For the filter.
The DetectorModes tell me what the status of the detector is. For example:
2 = System Okay
7 = Offline
However, When a detector is not in the DetectorStatus table. It obviously does not have any values in this table.
When this is the case, the mode of the detector is Unknown.
And i want to be able to filter on the Unknow system types.
What about this:
query = query.Where(d => d.Detectors.Count(t => t.DetectorStatus.Count() == 0) > 0);
But I would prefer Any() instead of Count()>0, if available.

how to show result using multiple Order by descending using linq query

I am having 3 criteria. I want to order these 3 types.
Who Paid with Master User
Who Update their Post Latest Date
Who Paid with Sub Master User
which one is having count it will come to top 15 Jobs.
My code here:
var orderMaster= _vasRepository.GetOrderDetails()
.Where(od => od.OrderMaster.OrganizationId != null &&
od.OrderId == od.OrderMaster.OrderId &&
od.OrderMaster.PaymentStatus == true &&
od.ValidityTill.Value >= currentdate)
.OrderByDescending(od => od.ValidityTill)
.Select(ord => ord.OrderMaster.Id.Value);
var updatedVacancyList = _repository.GetJobs()
.Where(c => c.UpdatedDate != null &&
updateFresh <= c.UpdatedDate)
.Select(c => c.Id);
var orderLatestUser = _vasRepository.GetOrderDetails()
.Where(od => od.OrderMaster.UserId != null &&
od.OrderMaster.PaymentStatus == true &&
freshUser <= od.ActivationDate &&
od.ValidityTill.Value >= currentdate)
.Select(c => c.OrderMaster.User.Id);
Then I check the count of those then assign to
List<int> lstMasterId = orderOrganization.ToList();
List<int>lstUpdatedJobsListId = updatedVacancyList.ToList();
List<int>lstUserListId= orderLatestUser.ToList();
Here i order the lists using query
Func<IQueryable<Job>, IOrderedQueryable<Job>> orderingFunc = query =>
{
if (orderMaster.Count() > 0)
return query.OrderByDescending(rslt =>
lstOrganizationId.Contains(rslt.OrganizationId))
.ThenByDescending(rslt=>lstUserListId.Contains(rslt.User.Id))
.ThenByDescending(rslt => lstUpdatedJobsListId.Contains(rslt.Id))
.ThenByDescending(rslt => rslt.CreatedDate);
else
return query.OrderByDescending(rslt => rslt.CreatedDate);
};
jobs = orderingFunc(jobs);
}
I want to show the lstUserListId at top of the result.. How to do this?

Distance in SQL using Distance()

I'm trying to get the points in a database that are at a distance of no more than 200 meters away, and i'm using the following code but it also retrieves all the points in the data base
var pin = from pinsA in db.PINS
.Where(p => p.PRIVACY == 0 || p.USER_ID == userId
&& (double)currentPoint.Distance(p.location) < 200.0)
.Select(pr => new { pr.PIN_ID, pr.TYPE, pr.location })
select new { pinsA.PIN_ID, pinsA.TYPE, pinsA.location } ;
You don't provide the specific conditions but I think you are missing parenthesis in your Where clause, try:
Where((p => p.PRIVACY == 0 || p.USER_ID == userId)
&& (double)currentPoint.Distance(p.location) < 200.0)
Although its a preference thing, I'm not sure on the need to mix-match the query "languages" (which probably isn't helping), nor the need for a "double" select.
I also agree with jnovo's post on that you are most likely missing parenthesis in your where clause, but try either of the following:
Option 1:
var pinsWithin200 = from pins in db.Pins
where ((pins.PRIVACY == 0 || pins.USER_ID == userId) && pins.location.Distance(currentPoint) <= 200)
select new
{
PIN_ID = pins.PIN_ID,
TYPE = pins.TYPE,
location = pins.location
};
var results = pinsWithin200.ToList();
Option 2:
var pinsWithin200 = db.Pins
.Where(p => (p.PRIVACY == 0 || p.USER_ID == userId) && p.location.Distance(currentPoint) <= 200)
.Select(p => new
{
PIN_ID = p.PIN_ID,
TYPE = p.TYPE,
location = p.location
};
var results = pinsWithin200.ToList();
Whichever you prefer, they are cleaner, and without the double-select. Also note its good practise to explicitly name your properties in anonymous types.

Categories

Resources