Ever time when I have many options to order and filter, in my repository I have using "switch" to decide, but the code is very duplicate.
How can I use the coditional order to remove the duplicate code?
Whould you have a solution to optimize this code?
Sample Code:
IEnumerable<Products> products;
switch (orderBy)
{
case "Create":
products = _GFazContext.Products
//... many conditions like:
.Where(r => (productId == null || r.ProductId == productId))//Duplicate code
.Where(r => (groupId == null || r.GroupId == groupId))//Duplicate code
.Where(r => (statusId == null || r.StatusId == statusId)) //Duplicate code
//Condition about the order
.Where(r => (data1 == null || r.CreateDate >= data1))
.Where(r => (data2 == null || r.CreateDate <= data2))
.Include(r => r.Group) //Duplicate code
//Specific order
.OrderBy(p => p.CreateDate)
.Skip(pagination.SkipRecords)//Duplicate code
.Take(pagination.PageSize);//Duplicate code
break;
case "Update":
products = _GFazContext.Products
//... many conditions like:
.Where(r => (productId == null || r.ProductId == productId))//Duplicate code
.Where(r => (groupId == null || r.GroupId == groupId))//Duplicate code
.Where(r => (statusId == null || r.StatusId == statusId)) //Duplicate code
//conditions about the order
.Where(r => (data1 == null || r.LastUpdate >= data1))
.Where(r => (data2 == null || r.LastUpdate <= data2))
.Include(r => r.Group) //Duplicate code
//Specific orders
.OrderBy(p => p.LastUpdate)
.Skip(pagination.SkipRecords)//Duplicate code
.Take(pagination.PageSize);//Duplicate code
break; break;
default:
products = _GFazContext.Products
//... many conditions like:
.Where(r => (productId == null || r.ProductId == productId))//Duplicate code
.Where(r => (groupId == null || r.GroupId == groupId))//Duplicate code
.Where(r => (statusId == null || r.StatusId == statusId)) //Duplicate code
//Condition about the order
.Where(r => (data1 == null || r.ReleaseDate >= data1))
.Where(r => (data2 == null || r.ReleaseDate <= data2))
.Include(r => r.Group) //Duplicate code
//Specific orders
.OrderBy(p => p.ReleaseDate)
.Skip(pagination.SkipRecords)//Duplicate code
.Take(pagination.PageSize);//Duplicate code
break;
}
return products;
Something like this
IQueryable<Products> products = _GFazContext.Products
.Where(r => (productId == null || r.ProductId == productId))
.Where(r => (groupId == null || r.GroupId == groupId))
.Where(r => (statusId == null || r.StatusId == statusId));
switch (orderBy)
{
case "Create":
products = products
.Where(r => (data1 == null || r.CreateDate >= data1))
.Where(r => (data2 == null || r.CreateDate <= data2))
.Include(r => r.Group)
.OrderBy(p => p.CreateDate);
break;
case "Update":
products = products
.Where(r => (data1 == null || r.LastUpdate >= data1))
.Where(r => (data2 == null || r.LastUpdate <= data2))
.Include(r => r.Group)
.OrderBy(p => p.LastUpdate);
break;
default:
products = products
.Where(r => (data1 == null || r.ReleaseDate >= data1))
.Where(r => (data2 == null || r.ReleaseDate <= data2))
.Include(r => r.Group)
.OrderBy(p => p.ReleaseDate);
break;
}
products = products
.Skip(pagination.SkipRecords)
.Take(pagination.PageSize);
return products;
Try This -
IEnumerable<Products> products;
products = _GFazContext.Products
.Where(r => (productId == null || r.ProductId == productId))
.Where(r => (groupId == null || r.GroupId == groupId))
.Where(r => (statusId == null || r.StatusId == statusId))
.Where(r => orderBy == "Create" ? (data1 == null || r.CreateDate >= data1) : (orderBy == "Update" ? (data1 == null || r.LastUpdate >= data1) : (data1 == null || r.ReleaseDate >= data1)))
.Where(r => orderBy == "Create" ? (data2 == null || r.CreateDate <= data2) : (orderBy == "Update" ? (data2 == null || r.LastUpdate <= data2) : (data2 == null || r.ReleaseDate <= data2)))
.Include(r => r.Group)
//Specific order
.OrderBy(p => orderBy == "Create" ? p.CreateDate : (orderBy == "Update"? p.LastUpdate : p.ReleaseDate))
.Skip(pagination.SkipRecords)
.Take(pagination.PageSize);
Related
I created where conditions with linq lambda expression for reporting. My conditions are running very slowly or it is throwing error.
Error Detail: Evoluation timed out.
How can i find correct query?
My codes:
var query = Worker.Members
.Where(u => string.IsNullOrEmpty(model.TcNumber) || u.TcNumber.Contains(model.TcNumber))
.Where(u => string.IsNullOrEmpty(model.FullName) || u.FullName.Contains(model.FullName))
.Where(u => model.BirthYear == null || u.BirthDate.Year >= model.BirthYear)
.Where(u => model.BirthYearLevel == null || u.BirthDate.Year <= model.BirthYearLevel)
.Where(u => model.BirthYearLevel == null || u.BirthDate.Year <= model.BirthYearLevel)
.Where(u => model.GenderId == null || u.GenderId == model.GenderId)
.Where(u => model.DistrictCode == null || u.Contacts.Any(c => c.DistrictCode == model.DistrictCode && c.IsActive))
.Where(u => model.StreetCode == null || u.Contacts.Any(c => c.StreetCode == model.StreetCode && c.IsActive))
.Where(u => model.ExteriorDoor == null || u.Contacts.Any(c => c.ExteriorDoor == model.ExteriorDoor && c.IsActive))
.Where(u => model.InteriorDoor == null || u.Contacts.Any(c => c.InteriorDoor == model.InteriorDoor && c.IsActive))
.Where(u => model.DisabledGroupId == null || u.Disableds.Any(d => d.ReportDisabledGroups.Any(c => c.DisabledGroupId == model.DisabledGroupId)))
.Where(u => model.ContributionTypeId == null || u.Demands.Any(d => d.ContributionTypeId == model.ContributionTypeId && !d.IsDeleted))
.Where(u => model.DemandStatusId == null || u.Demands.Any(d => d.DemandStatusId == model.DemandStatusId && !d.IsDeleted))
.Where(u => model.DemandDateStart == null || u.Demands.Any(d => d.DemandDate >= model.DemandDateStart && !d.IsDeleted))
.Where(u => model.DemandDateEnd == null || u.Demands.Any(d => d.DemandDate <= model.DemandDateEnd && !d.IsDeleted))
.Where(u => u.IsTcCitizen == model.IsForeign)
.Where(u => u.IsDisabled == model.IsDisabled)
.Where(u => u.IsAlive == model.IsAlive);
The correct pattern (assuming Worker.Members is an IQueryable, not an IEnumerable) here is to conditionally add the criteria, like this:
var query = Worker.Members;
if (!string.IsNullOrEmpty(model.TcNumber))
query = query.Where(u => u.TcNumber.Contains(model.TcNumber));
if (!string.IsNullOrEmpty(model.FullName)
query = query.Where(u => u.FullName.Contains(model.FullName));
if (!model.BirthYear == null)
query = query.Where(u => u.BirthDate.Year >= model.BirthYear);
. . .
Did you check this?
Here detailed descriptions are given.
I am trying to get the result based upon the values of variables temp_DestinationGroupName, temp_CountryName and temp_RateTypeId.
If any of these variables are null or 0, it should not be included in where clause and rest statements should work and bring the result. I am getting zero rows using this query. Kindly suggest me something with these conditions in where clause. i tried following solutions on stackoverflow but still not getting the desired result.
var Rows = _CustomerRatesList.Where(w => (w.Id != rates.Id)
&& (w.DestinationGroupName == temp_DestinationGroupName || temp_DestinationGroupName!= null)
&& (w.CountryName == temp_CountryName || temp_CountryName!=null)
&& (w.RateTypeId == temp_RateTypeId || temp_RateTypeId !=0));
(w.DestinationGroupName == temp_DestinationGroupName || temp_DestinationGroupName!= null)
Your condition here will return true as long as your input variable temp_DestinationGroupName is not null. I don't think that's what you had in mind.
You can split in many Where to make your request more readable :
var Rows = _CustomerRatesList.Where(w => w.Id != rates.Id)
.Where(w => w.DestinationGroupName != temp_DestinationGroupName || temp_DestinationGroupName != null)
.Where(w => w.CountryName != temp_CountryName || temp_CountryName != null)
.Where(w => w.RateTypeId != temp_RateTypeId || temp_RateTypeId !=0);
Notice that you must use != in first conditioon of all Where, so you'll get all data except when it's null. In your logic, may be the conditions will be == :
var Rows = _CustomerRatesList.Where(w => w.Id != rates.Id)
.Where(w => w.DestinationGroupName == temp_DestinationGroupName || temp_DestinationGroupName == null)
.Where(w => w.CountryName == temp_CountryName || temp_CountryName == null)
.Where(w => w.RateTypeId == temp_RateTypeId || temp_RateTypeId ==0);
Each Where result is an IEnumerable, Rows will be a IEnumerable. If you want a List, just add .ToList()
I got the solution to this problem, now i am getting filtered result.
Thank you all for your time :)
var otherRows = _CustomerRatesList.Where(w => w.Id != rates.Id)
.Where(w => w.DestinationGroupName == temp_DestinationGroupName || temp_DestinationGroupName == null)
.Where(w => w.CountryName == temp_CountryName || temp_CountryName == null)
.Where(w => w.RateTypeId == temp_RateTypeId || temp_RateTypeId == 0);
In a Linq query I need to filter appointments by Date and Local, Date or Local.
So if GivenDate and GivenLocal are not null I need to filter by GivenDate and GivenLocal:
appointments.Where(x => x.Date == x.GivenDate && x.Local == x.GivenLocal)
If GivenDate is null then the filter would be done by Local:
appointments.Where(x => x.Local == x.GivenLocal)
And if GivenLocal is null then filter by Date:
appointments.Where(x => x.Date == x.GivenDate)
Is it possible to do this with one query instead of using IF statements and 3 queries?
appointments.Where(x =>
(x.GivenDate == null || x.Date == x.GivenDate) &&
(x.GivenLocal == null || x.Local == x.GivenLocal) && )
appointments.Where(x => ((x.GivenDate != null && x.GivenLocal != null && x.Date == x.GivenDate && x.Local == x.GivenLocal) || (x.GivenDate == null && x.Local == x.GivenLocal ) || (x.GivenLocal == null && x.Date == x.GivenDate)))
Given the following:
var questions = _questionsRepository
.GetAll()
.Where(q => q.Problem.SubTopicId == subTopicId || subTopicId == 0)
.Where(q => q.QuestionStatusId == questionStatusId || questionStatusId == 0)
.Where(q => q.AssignedTo == assignedTo || assignedTo == "0")
.Where(q => q.ModifiedBy == modifiedBy || modifiedBy == "0")
.Include(q => q.Problem)
.Include(q => q.Answers)
.ToList();
Is there a way I can return the question and answer data plus only the fields SubTopicId and ProblemId from the Problem table/class ?
Try adding select at the end of query
var problems = _questionsRepository
.GetAll()
.Where(q => q.Problem.SubTopicId == subTopicId || subTopicId == 0)
.Where(q => q.QuestionStatusId == questionStatusId || questionStatusId == 0)
.Where(q => q.AssignedTo == assignedTo || assignedTo == "0")
.Where(q => q.ModifiedBy == modifiedBy || modifiedBy == "0")
.Include(q => q.Problem)
.Include(q => q.Answers)
.Select(x=>new
{
SubTopicId = x.Problem.SubTopicId,
ProblemId = x.Problem.ProblemId
}).ToList();
I have those statements who checks if I have all the answers in a Grid. Each row is identified by a ContextYID.
I would like to know if i can combine those LinQ query and convert it directly to a True/False Statement.
int nbRow = Answers.Where(a => a.FieldId == result.Id && a.FieldYId == fieldYAxi.Id)
.Select(a => a.ContextYId)
.Distinct()
.Count();
int nbAnswer = Answers.Count(a =>
a.FieldId == result.Id &&
a.FieldXId == fieldXAxi.Id &&
a.FieldYId == fieldYAxi.Id);
if (nbAnswer != nbRow)
return false;
else
return true;
I think this is an improvement, because the FieldId and FieldYID only need to be compared once, and I simplified your return statements into one line.
var matchingAnswers = Answers.Where(a => a.FieldId == result.Id
&& a.FieldYId == fieldYAxi.Id).ToList();
int nbRow = matchingAnswers
.Select(a => a.ContextYId)
.Distinct()
.Count();
int nbAnswer = matchingAnswers.Count(a => a.FieldXId == fieldXAxi.Id);
return nbAnswer == nbRow;
If you like, you can shorten this by merging the last few lines:
var matchingAnswers = Answers.Where(a => a.FieldId == result.Id
&& a.FieldYId == fieldYAxi.Id).ToList();
return matchingAnswers.Count(a => a.FieldXId == fieldXAxi.Id) ==
matchingAnswers.Select(a => a.ContextYId).Distinct().Count();
Wouldn't equals work?
return Answers.Where(a => a.FieldId == result.Id && a.FieldYId == fieldYAxi.Id)
.Select(a => a.ContextYId)
.Distinct()
.Count()
.Equals(Answers.Count(a =>
a.FieldId == result.Id &&
a.FieldXId == fieldXAxi.Id &&
a.FieldYId == fieldYAxi.Id));
I think this should work. Is there a particular reason you want to do this?
return Answers.Where(a => a.FieldId == result.Id && a.FieldYId == fieldYAxi.Id)
.Select(a => a.ContextYId)
.Distinct()
.Count()
== Answers.Count(a => a.FieldId == result.Id
&& a.FieldXId == fieldXAxi.Id
&& a.FieldYId == fieldYAxi.Id)
I think this is functionally equivalent to what are doing (but I do wonder what you're doing for the duplicate ContextYIds that satisfy nbAnswer multiple times):
var distinctContextYIds = new HashSet<int>();
return 0 == Answers.Where(a => a.FieldId == result.Id && a.FieldYId == fieldYAxi.Id)
.Aggregate(0, (tally, answer) =>
{
if (distinctContextYIds.Add(answer.ContextYId))
tally += 1;
if (answer.FieldXId == fieldXAxi.Id)
tally -= 1;
return tally;
});