Linq - Dynamic Condition - c#

I have the following query :-
I want to add one more condition which is dynamic, so if user passes DATEOFBIRTH it should be e.DateOfBirth <= date.
var data = ctx.Employee.Where(e => e.Id == Id
&& e.Category == Category
&& e.DateOfJoining <= date)
.Select(e => e)
.ToList();
How to condition dynamically?

You can use reflection to solve this problem but there is another idea that may helps you:
var criteria = new Dictionary<string, Func<Employee, bool>>();
var date = DateTime.Now; //or any other value
//Initialize your criterias
criteria.Add("DATEOFBIRTH", e => e.DateOfBirth <= date);
criteria.Add("DateOfJoining", e => e.DateOfJoining <= date);
var selectedValue = "DATEOFBIRTH";
var data = ctx.Employee.Where(e => e.Id == id &&
e.Category == Category &&
criteria[selectedValue](e)).ToList();
So if you change the selectedValue the output will be based on corresponding criteria you are looking for.

From your comment:
If the DateOfBirth is choosen, there where condition should be appended
by one more condition e.DateOfBirth <= date.. if user chooses
DateOfAnniversary then it should be e.DateOfAnniversary <= date
Then you could use:
var data = ctx.Employee
.Where(e => e.Id == Id && e.Category == Category && e.DateOfJoining <= date);
Now, assuming that filterbyDateOfBirth and filterbyDateOfAnniversary are bools:
if(filterbyDateOfBirth)
data = data.Where(e => e.DateOfBirth <= date);
if(filterbyDateOfAnniversary)
data = data.Where(e => e.DateOfAnniversary <= date);
var list = data.ToList();
Due to LINQ's deferred execution the database is queried just once at ToList.

Sounds like you're trying to do the following:
var employees = ctx.Employee.Where(e => e.Id == Id
&& e.Category == Category
&& e.DateOfJoining <= date);
if (!string.IsNullOrWhiteSpace(DATEOFBIRTH))
{
employees = employees.Where(e => e.DateOfBirth <= DATEOFBIRTH);
}
var data = employees.ToList();
You could also do the following, which is more concise, but since it looks like you are querying a database here, I would prefer the above approach since it doesn't include anything unnecessary in the query.
var data = ctx.Employee.Where(e => e.Id == Id &&
e.Category == Category &&
e.DateOfJoining <= date &&
(string.IsNullOrWhiteSpace(DATEOFBIRTH) ||
e.DateOfBirth <= DATEOFBIRTH))
.ToList();

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))

How to total quantity based on date range from another table?

how to total quantity based on date range from another table?
var items = entity.ItemHeaders.Where(x => x.date >= _dateFrom && x.date <= dateTo);
var tQty = entity.ItemContents.Where(x => x.Warehouse == dto.Warehouse).Sum(x => x.Quantity);
the problem is I don't have any idea how to connect them.
To join the entity by HeaderNumber and sum the total:
var total = (from header in entity.ItemHeaders
from content in entity.ItemContents
where header.date >= _dateFrom && header.date <= dateTo
&& content.Warehouse == dto.Warehouse
&& header.ID = content.HeaderNumber
select content.Quantity).Sum();
Assuming you are using Entity Framework, it will be easier if you have a Navigation Property defined in ItemContent for the ItemHeader. e.g.:
public virtual ItemHeader Header {get; set;}
Then the query could be:
var total = entity.ItemContents
.Where(x=> x.Header.date >= _dateFrom && x.Header.date <= dateTo
&& x.Warehouse == dto.Warehouse)
.Sum(x => x.Quantity);

Lambda Expression for Not In a Collection

I have 3 tables
eTrip
Country | eProfile
eProfile
Documents (collection of Document)
Documents
Type | ExpiryDate | Country
I am trying to get a collection of eTrips in a search api. There are several conditions that need to be met for an eTrip.
Each employee can hold multiple documents (visas, passports, etc). For an eTrip to be valid we need to make sure the eTrip.Country != the country of a valid passport (future expiry date) document.
How can we write a lambda expression to accomplish this?
The code that I have so far is something like this
var query = context.eTrip.AsQueryable();
query = query.Where(e => e.validTrip == true);
var docs = query.Select(e => e.eProfile.Documents);
foreach (Documents d in docs)
{
if (d.DocumentTypeCode == "Passport" && d.ExpiryDate != null && d.ExpiryDate > DateTime.Now)
{
query = query.Where(e => e.Country != d.Country);
}
}
I need to write the filter for the country now and I am not sure how we can do it for a collection.
you can extend your Where clause with an Any subquery on Documents
query = query.Where(e => e.validTrip == true && e.eProfile.Documents.Any(a=>a.DocumentTypeCode == "Passport" && a.ExpiryDate.HasValue && a.ExpiryDate.Value > DateTime.Now && e.Country!=d.Country));
Try that:
// your part
var query = context.eTrip.AsQueryable();
query = query.Where(e => e.validTrip == true);
var docs = query.Select(e => e.eProfile.Documents);
// get countries for which there are no documents with future date
var myCountryQuery = query.Where(x => !docs
.Where(d => d.DocumentTypeCode == "Passport" && d.ExpiryDate != null && d.ExpiryDate > DateTime.Now)
.Any(d => d.Country != x.Country)
);

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?

Comma separated List in linq select

I have Table HR_Travel(TravelID, TravelCode....) and HR_TravelDocuments(TravelDocID, TravelID, DocUrl)
FromDate = FromDate.AddDays(1);
ToDate = ToDate.AddDays(1);
List<dynamic> Lst = new List<dynamic>();
var queryTravelDetails = from t in db.HR_TravelDetails
where ((t.StatusDate >= FromDate && t.StatusDate <= ToDate)
&& (t.EmpID == EmpID || EmpID == 0) && (t.TravelStatus == TravelStatus || TravelStatus == "All"))
orderby t.StatusDate descending
select new
{
TravelID = t.TravelID,
TravelSubID = db.HR_TravelDetails.Where(i => i.TravelID == 0).FirstOrDefault().TravelID == null ? 0 : db.HR_TravelDetails.Where(i => i.TravelID == 0).FirstOrDefault().TravelID,
t.TravelCode,
t.EmpID,
EmpName = db.EE_Employee.Where(i => i.EmpID == t.EmpID).FirstOrDefault().EmpName,
t.CellNo,
t.BoardingForm,
t.DestinationTO,
t.JournyDate,
t.Purpose,
t.Organization,
t.TravelStatus,
DocUrl = DocUrl = string.Join(",",( db.HR_TravelDocuments.Where(i => i.TravelID == t.TravelID && i.TravelSubID == 0).Select(i => i.DocUrl).ToList()))
};
foreach (var element in queryTravelDetails)
{
Lst.Add(element);
}
Gives the following error:
LINQ to Entities does not recognize the method 'System.String Join[String](System.String, System.Collections.Generic.IEnumerable`1[System.String])' method, and this method cannot be translated into a store expression.
The Join() method can't be used in LINQ expressions, because it cannot translate from CLR to T-SQL. Another example is that you can't use:
var itemCount = db.Table.Count(p => p.Something == SomeFunction(someVariable));
You should move the method call outside the LINQ statement:
var anotherVariable = SomeFunction(someVariable);
var itemCount = db.Table.Count(p => p.Something == anotherVariable);
I hope I explained in a good way.
EDIT: As seen in the comments before, you can also use ToArray() and when the data is loaded locally you can use functions in statements freely.

Categories

Resources