Optimize LINQ queries - c#

I'd like to optimize my LINQ query.
Orders = (from m in dataContext.SupplierOrdersViews
where (fromDate != toDate ?
m.RecordCreated >= fromDate && m.RecordCreated <= toDate :
(m.RecordCreated.Value.Year == fromDate.Year &&
m.RecordCreated.Value.Month == fromDate.Month &&
m.RecordCreated.Value.Day == fromDate.Day))
select new
{
id = m.ID,
RecordCreated = m.RecordCreated,
RecordDeleted = m.RecordDeleted,
Status = m.Status,
DepRunningNo = m.DepRunningNo,
Name = m.Name,
Address1 = m.Address1,
VehicleRegNo = m.VehicleRegNo,
ProductName = m.ProductName,
Tare = m.Tare < m.Gross ? m.Tare : m.Gross,
Gross = m.Tare < m.Gross ? m.Gross : m.Tare,
NetWeight = m.NetWeight,
NetPrice = m.NetPrice
}).OrderBy(m => m.RecordCreated).ThenByDescending(m => m.Status != 2).ToList();
I think the issue is with these lines:
Tare = m.Tare < m.Gross ? m.Tare : m.Gross,
Gross = m.Tare < m.Gross ? m.Gross : m.Tare,
How does this work behind the scenes, and is there a better way to accomplish it? I'm happy that it works but its not perfect. This populates a grid with (using default filters) 77 records and it takes like 3 seconds...way too long!
Is there a better way to assign gross/tares? I need to do a check similar to what I have here because the weights are ambiguously stored in the database.

fromDate and toDate are not variable per row; they're fixed for the whole query, so rather than making that check a part of the query, you can do it before the query:
Expression<Func<SupplierOrders, bool>> filter;
if(fromDate != toDate)
filter = m => m.RecordCreated >= fromDate && m.RecordCreated <= toDate;
else
filter = m => (m.RecordCreated.Value.Year == fromDate.Year &&
m.RecordCreated.Value.Month == fromDate.Month &&
m.RecordCreated.Value.Day == fromDate.Day);
dataContext.SupplierOrdersViews.Where(filter)
//the rest of the query goes here

Related

How to set date between AM/PM 24-hour

I have 2 parameters. one is defaultFromD and another is defaualtToD. if I give 2 date range for this x.CreatedOn >= defaultFromD && x.CreatedOn <= defaultToD
x.CreatedOn >= '2021-10-17' && x.CreatedOn <= '2021-10-20'
its working. but if I give same date for this two parameters this condition is not working.
x.CreatedOn >= '2021-10-20' && x.CreatedOn <= '2021-10-20'
I want to knw how to pass this 2 logic in one condition. Please help me to resolve this issue.
Thank you...
public ResponseDTO<IQueryable<LabRequestForLabOrderDTO>> GetApprovedLabRequestsQueryable(DateTime defaultFromD, DateTime defaultToD)
{
var resp = ResponseBuilder.Build<IQueryable<LabRequestForLabOrderDTO>>();
var reqs = this.labRequestRepository.GetAllActive().Where(x => x.IsActive && x.TrxStatus == 1 && x.InvoiceStatus == "Approved"
&& x.CreatedOn >= defaultFromD && x.CreatedOn <= defaultToD)
.Select(x => new LabRequestForLabOrderDTO
{
Clinic = x.Clinic,
LabOrderCreated = x.LabOrderCreated,
InvoiceStatus = x.InvoiceStatus,
CreatedOn = x.CreatedOn
}).AsQueryable();
resp.AddSuccessResult(reqs);
return resp;
}
Try this
x.CreatedOn.AddDays(-1) > defaultFromD && x.CreatedOn.AddDays(1) < defaultToD
This is due to DateTime and Date Formate.
You should try the following way.
Consider you column CreatedOn datatype is: DateTime
x.CreatedOn.Date >= '2021-10-20' && x.CreatedOn.Date <= '2021-10-20'
This work for me
var todate = defaultToD.AddDays(1);
x.CreatedOn >= defaultFromD && x.CreatedOn <= todate

How to select which where clause to use based off a variable in c#?

I am trying to condense my code in order to select which where clause the user would like to use based off a c# variable.
I have tried using parameters and some other ideas I saw online, but could not get it to work.
if (btnUseDateRange.Text == "Disabled")
{
var queryTestedControls =
(from t in dbContext.UUT_RESULT
where t.PART_NAME.Contains(ControlSelected)
&& t.UUT_SERIAL_NUMBER.CompareTo(BarcodeStart) >= 0
&& t.UUT_SERIAL_NUMBER.CompareTo(BarcodeEnd) <= 0
select t.UUT_SERIAL_NUMBER).Count();
var queryPassedControls =
(from t in dbContext.UUT_RESULT
where t.PART_NAME.Contains(ControlSelected)
&& t.UUT_SERIAL_NUMBER.CompareTo(BarcodeStart) >= 0
&& t.UUT_SERIAL_NUMBER.CompareTo(BarcodeEnd) <= 0
&& t.UUT_STATUS == "Passed"
select t.UUT_SERIAL_NUMBER).Count();
lblTested.Text = queryTestedControls.ToString();
lblPassed.Text = queryPassedControls.ToString();
}
else if (btnUseDateRange.Text == "Enabled")
{
var queryTestedControls =
(from t in dbContext.UUT_RESULT
where t.PART_NAME.Contains(ControlSelected)
&& t.START_DATE_TIME >= DateStart
&& t.START_DATE_TIME <= DateEnd
select t.UUT_SERIAL_NUMBER).Count();
var queryPassedControls =
(from t in dbContext.UUT_RESULT
where t.PART_NAME.Contains(ControlSelected)
&& t.START_DATE_TIME >= DateStart
&& t.START_DATE_TIME <= DateEnd
&& t.UUT_STATUS == "Passed"
select t.UUT_SERIAL_NUMBER).Count();
lblTested.Text = queryTestedControls.ToString();
lblPassed.Text = queryPassedControls.ToString();
}
My code will be very long, because I am doing a count for Passed, Failed, Aborted, and Other. Is there a way to condense the query? Based off the button in the if statement, the user is selecting to either query with a barcode range or a datetime range.
Somewhat shorter
var queryTestedControls = from t in dbContext.UUT_RESULT
where t.PART_NAME.Contains(ControlSelected)
select t;
var queryPassedControls = from t in dbContext.UUT_RESULT
where t.PART_NAME.Contains(ControlSelected)
select t;
if (btnUseDateRange.Text == "Disabled")
{
lblTested.Text = queryTestedControls.Where(t => t.UUT_SERIAL_NUMBER.CompareTo(BarcodeStart) >= 0 &&
t.UUT_SERIAL_NUMBER.CompareTo(BarcodeEnd) <= 0).Count().ToString();
lblPassed.Text = queryPassedControls.Where(t => t.UUT_SERIAL_NUMBER.CompareTo(BarcodeStart) >= 0 &&
t.UUT_SERIAL_NUMBER.CompareTo(BarcodeEnd) <= 0 &&
t.UUT_STATUS == "Passed").Count().ToString();
}
else if (btnUseDateRange.Text == "Enabled")
{
lblTested.Text = queryTestedControls.Where(t => t.START_DATE_TIME >= DateStart &&
t.START_DATE_TIME <= DateEnd).Count().ToString();
lblPassed.Text = queryPassedControls.Where(t => t.START_DATE_TIME >= DateStart &&
t.START_DATE_TIME <= DateEnd &&
t.UUT_STATUS == "Passed").Count().ToString();
}

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

Linq - Dynamic Condition

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

C# Linq Where Date Between 2 Dates

I'm trying to get my linq statement to get me all records between two dates, and I'm not quite sure what I need to change to get it to work: (a.Start >= startDate && endDate)
var appointmentNoShow =
from a in appointments
from p in properties
from c in clients
where a.Id == p.OID && (a.Start.Date >= startDate.Date && endDate)
Just change it to
var appointmentNoShow = from a in appointments
from p in properties
from c in clients
where a.Id == p.OID &&
(a.Start.Date >= startDate.Date && a.Start.Date <= endDate)
var appointmentNoShow = from a in appointments
from p in properties
from c in clients
where a.Id == p.OID
where a.Start.Date >= startDate.Date
where a.Start.Date <= endDate.Date
var QueryNew = _context.Appointments.Include(x => x.Employee).Include(x => x.city).Where(x => x.CreatedOn >= FromDate).Where(x => x.CreatedOn <= ToDate).Where(x => x.IsActive == true).ToList();
So you are scrolling down because the Answers do not work:
This works like magic (but they say it has efficiency issues for big data, And you do not care just like me)
1- Data Type in Database is "datetime" and "nullable" in my case.
Example data format in DB is like:
2018-11-06 15:33:43.640
An in C# when converted to string is like:
2019-01-03 4:45:16 PM
So the format is :
yyyy/MM/dd hh:mm:ss tt
2- So you need to prepare your datetime variables in the proper format first:
Example 1
yourDate.ToString("yyyy/MM/dd hh:mm:ss tt")
Example 2 - Datetime range for the last 30 days
DateTime dateStart = DateTime.Now.AddDays(-30);
DateTime dateEnd = DateTime.Now.AddDays(1).AddTicks(-1);
3- Finally the linq query you lost your day trying to find (Requires EF 6)
using System.Data.Entity;
_dbContext.Shipments.Where(s => (DbFunctions.TruncateTime(s.Created_at.Value) >= dateStart && DbFunctions.TruncateTime(s.Created_at.Value) <= dateEnd)).Count();
To take time comparison into account as well :
(DbFunctions.CreateDateTime(s.Created_at.Value.Year, s.Created_at.Value.Month, s.Created_at.Value.Day, s.Created_at.Value.Hour, s.Created_at.Value.Minute, s.Created_at.Value.Second) >= dateStart && DbFunctions.CreateDateTime(s.Created_at.Value.Year, s.Created_at.Value.Month, s.Created_at.Value.Day, s.Created_at.Value.Hour, s.Created_at.Value.Minute, s.Created_at.Value.Second) <= dateEnd)
Note the following method mentioned on other stackoverflow questions and answers will not work correctly:
....
&&
(
s.Created_at.Value.Day >= dateStart.Day && s.Created_at.Value.Day <= dateEnd.Day &&
s.Created_at.Value.Month >= dateStart.Month && s.Created_at.Value.Month <= dateEnd.Month &&
s.Created_at.Value.Year >= dateStart.Year && s.Created_at.Value.Year <= dateEnd.Year
)).count();
if the start day was in this month for example and the end day is on the next month, the query will return false and no results, for example:
DatabaseCreatedAtItemThatWeWant = 2018/12/05
startDate = 2018/12/01
EndDate = 2019/01/04
the query will always search for days between 01 and 04 without taking the "month" into account, so "s.Created_at.Value.Day <= dateEnd.Day" will fail
And in case you have really big data you would execute Native SQL Query rather than linq
...
... where Shipments.Created_at BETWEEN CAST(#Created_at_from as datetime) AND CAST(#Created_at_to as datetime))
....
Thanks
If someone interested to know how to work with 2 list and between dates
var newList = firstList.Where(s => secondList.Any(secL => s.Start > secL.RangeFrom && s.End < secL.RangeTo))
public List<tbltask> gettaskssdata(int? c, int? userid, string a, string StartDate, string EndDate, int? ProjectID, int? statusid)
{
List<tbltask> tbtask = new List<tbltask>();
DateTime sdate = (StartDate != "") ? Convert.ToDateTime(StartDate).Date : new DateTime();
DateTime edate = (EndDate != "") ? Convert.ToDateTime(EndDate).Date : new DateTime();
tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).
Where(x => x.tblproject.company_id == c
&& (ProjectID == 0 || ProjectID == x.tblproject.ProjectId)
&& (statusid == 0 || statusid == x.tblstatu.StatusId)
&& (a == "" || (x.TaskName.Contains(a) || x.tbUser.User_name.Contains(a)))
&& ((StartDate == "" && EndDate == "") || ((x.StartDate >= sdate && x.EndDate <= edate)))).ToList();
return tbtask;
}
this my query for search records based on searchdata and between start to end date
If you have date interval filter condition and you need to select all records which falls partly into this filter range. Assumption: records has ValidFrom and ValidTo property.
DateTime intervalDateFrom = new DateTime(1990, 01, 01);
DateTime intervalDateTo = new DateTime(2000, 01, 01);
var itemsFiltered = allItems.Where(x=>
(x.ValidFrom >= intervalDateFrom && x.ValidFrom <= intervalDateTo) ||
(x.ValidTo >= intervalDateFrom && x.ValidTo <= intervalDateTo) ||
(intervalDateFrom >= x.ValidFrom && intervalDateFrom <= x.ValidTo) ||
(intervalDateTo >= x.ValidFrom && intervalDateTo <= x.ValidTo)
);
I had a problem getting this to work.
I had two dates in a db line and I need to add them to a list for yesterday, today and tomorrow.
this is my solution:
var yesterday = DateTime.Today.AddDays(-1);
var today = DateTime.Today;
var tomorrow = DateTime.Today.AddDays(1);
var vm = new Model()
{
Yesterday = _context.Table.Where(x => x.From <= yesterday && x.To >= yesterday).ToList(),
Today = _context.Table.Where(x => x.From <= today & x.To >= today).ToList(),
Tomorrow = _context.Table.Where(x => x.From <= tomorrow & x.To >= tomorrow).ToList()
};
You can use DbFunctions.TruncateTime(StartDateTime) To remove the time from datetime
var appointmentNoShow =
from a in appointments
from p in properties
from c in clients
where a.Id == p.OID && (DbFunctions.TruncateTime(a.Start) >= DbFunctions.TruncateTime(startDate) && endDate)

Categories

Resources