select records for this month ONLY - c#

List<ActionPerformed> EndOfMonthPLUs = new List<ActionPerformed>();
List<ActionPerformed> AllPLUs = db.ActionPerformeds.ToList();
foreach (ActionPerformed ap in AllPLUs)
{
if (ap.File_Name == "PLU" && ap.Status == "Processed" && ap.Date == ??)
{
EndOfMonthPLUs.Add(ap);
}
}
I also want to add another query: && ap.Date == get all the files for this month.
So I have string date = todaysDate.ToString("MMMM, yyyy");
What now?

Assuming ap.Date is a DateTime, you could check the month and year are identical:
var now = DateTime.Now;
foreach (ActionPerformed ap in AllPLUs)
{
if (ap.File_Name == "PLU"
&& ap.Status == "Processed"
&& ap.Date.Month == now.Month
&& ap.Date.Year == now.Year)
{
EndOfMonthPLUs.Add(ap);
}
}

Compare the Month and Year properties on the Date to those of the current DateTime:
var AllPLUs = db.ActionPerformeds.ToList();
var now = DateTime.Now;
var EndOfMonthPLUs = AllPLUs
.Where(ap =>
ap.File_Name == "PLU" &&
ap.Status == "Processed" &&
ap.Date.Month == now.Month &&
ap.Date.Year == now.Year)
.ToList();
I assume that the "db" variable refers to an Entity Framework context. If so, and if you don't have any further requirements for the list containing ALL the PLUs, you may wish to perform some or all of this filtering as part of the EF query.

If I am not missing something, and your ap.Date property is a DateTime, could you just do this?
foreach (ActionPerformed ap in AllPLUs)
{
if (ap.File_Name == "PLU" && ap.Status == "Processed" &&
ap.Date.Month == DateTime.Today.Month)
{
EndOfMonthPLUs.Add(ap);
}
}

I think that
ap.Date.ToString("MMMM, yyyy") == date
is the answer you're looking for... alternatives could be
ap.Date.Month == DateTime.Now.Month && ap.Date.Year == DateTime.Now.Year
or since you are using entities, a linq query could apply
var aps = from ap in AllPLUs
where ap.File_Name == "PLU"
&& ap.Status == "Processed"
&& ap.Date.Month == DateTime.Now.Month
&& ap.Date.Year == DateTime.Now.Year
select ap
then
foreach(ActionPerformed ap in aps) { }

Related

How to split string in c# linq?

I have this
from d in db.v_Report_CompanySearches
orderby d.InquiryLogID descending
where (mPersonName == null || d.AccountName.ToLower() == mPersonName || d.PersonName.ToLower() == mPersonName) &&
(mCompanyName == null || TagsContain(d.CompanySearchTerm, mCompanyName)) &&
d.CreateDT >= mFrom && d.CreateDT <= mTo
select (d);
and
private bool TagsContain(string terms, string val)
{
string[] tags = terms.ToLower().Split(';');
return tags.Contains(val.ToLower());
}
but it crashes with not supported error. I think it's because I'm using a custom function TagsContain. How can I do that function in linq without custom stuff?
Thanks
Id TagsContain isn't supported by EF and have an underlying SQL function, it will crash. That's exactly what is happening here.
This however, should work:
from d in db.v_Report_CompanySearches
orderby d.InquiryLogID descending
where (mPersonName == null || d.AccountName.ToLower() == mPersonName || d.PersonName.ToLower() == mPersonName) &&
(mCompanyName == null || d.CompanySearchTerm.Contains(mCompanyName)) &&
d.CreateDT >= mFrom && d.CreateDT <= mTo
select (d);
Provider not able convert your custom function the sql. And I afraid split is one of the functions which not supported for generating sql.
You can use it without .Split
var query =
db.v_Report_CompanySearches
.Where(report => report.CreateDT >= from)
.Where(report => report.CreateDT <= to);
if (String.IsNullOrEmpty(personName) == false)
{
query = query.Where(report => report.AccountName.ToLower() == personName ||
report.PersonName.ToLower() == personName);
}
if (String.IsNullOrEmpty(companyName) == false)
{
query = query.Where(report => report.CompanySearchTerm.StartsWith($"{companyName};") ||
report.CompanySearchTerm.Contains($";{companyName};")) ||
report.CompanySearchTerm.EndsWith($";{companyName}"))
}
var result = query.OrderByDescending(report => report.InquiryLogID).ToList();
What Fabio said is right. Split function of c# can not be converted into SQL query. So, you have one way here
Get all the values from DB into C# List object and then apply the split filter over it.
var myListObject = (from d in db.v_Report_CompanySearches
orderby d.InquiryLogID descending
where (mPersonName == null || d.AccountName.ToLower() == mPersonName || d.PersonName.ToLower() == mPersonName) &&
d.CreateDT >= mFrom && d.CreateDT <= mTo
select (d)).ToList();
Then
var afterFilterObject = myListObject.Where(d => (d.mCompanyName == null || TagsContain(d.CompanySearchTerm, mCompanyName))).ToList();
Method to be called
private bool TagsContain(string terms, string val)
{
string[] tags = terms.ToLower().Split(';');
return tags.Contains(val.ToLower());
}

IQueryable with only optional parameters

I currently have the following method:
public List<Order> GetOrders(int profileId, string timeSpan, string workOrd, string partNo, bool includeDeleted)
{
DateTime startDate = DateTime.Now;
DateTime endDate = DateTime.Now;
string[] times = (!string.IsNullOrWhiteSpace(timeSpan)) ? timeSpan.Trim().Split('-') : new string[] { "", "" };
if (!string.IsNullOrWhiteSpace(times[0]) && !string.IsNullOrWhiteSpace(times[0]))
{
startDate = DateTime.Parse(times[0]).Date;
endDate = DateTime.Parse(times[1]).Date;
}
//New Real Query
IQueryable<Order_Travel> otQuery = _context.Order_Travels.Where(x =>
(profileId != 0 || x.Profile.ProfileID == profileId)
&& ((timeSpan == null || timeSpan.Trim() == "") || ((DbFunctions.TruncateTime(x.TimeRecieved) >= startDate)
&& (DbFunctions.TruncateTime(x.TimeRecieved) <= endDate)))
&& ((workOrd == null || workOrd.Trim() == "") || x.Order.WorkOrdNo == workOrd)
&& ((partNo == null ||partNo.Trim() == "") || x.Order.PartNo == partNo)
&& (!includeDeleted || x.Aborted == true));
//The results is now in order_travel. Under here binding them to a list of orders with only the respective orderTravels included.
List<Order> orders = new List<Order>();
List<Order_Travel> ots = otQuery.ToList();
foreach (Order_Travel ot in ots)
{
var OrderInList = orders.FirstOrDefault(X => X == ot.Order);
if (OrderInList == null)
{
orders.Add(ot.Order);
OrderInList = orders.FirstOrDefault(X => X == ot.Order);
OrderInList.OrderTravels.Clear();
OrderInList.OrderTravels.Add(ot);
}
else
{
OrderInList.OrderTravels.Add(ot);
}
}
return orders;
}
What I need it to do, is (as I've attempted) to make a call, finding all Order_Travel objects that match the paramters sent to it. If some (or all) are left blank, it takes everything, regardless of the values.
The code right now, does not return anything, if a blank search is made (a search that does not have any parameters), and I can not see what could be the issue. I have tried debugging it, but with no luck.
Any help would be greatly appreciated!
Thanks!
Filter one option at a time, instead of trying to put everything into a single expression:
IQueryable<T> query = all; // start with everything
if (IsPresent(option1))
{
query = query.Where(t => t.XXX == option1);
}
Example
IQueryable<Order_Travel> otQuery = _context.Order_Travels;
if (profileId != 0)
{
otQuery = otQuery.Where(x => x.Profile.ProfileID == profileId);
}
if (timeSpan != null && timeSpan.Trim() != "")
{
otQuery = otQuery.Where(x => DbFunctions.TruncateTime(x.TimeRecieved) >= startDate &&
DbFunctions.TruncateTime(x.TimeRecieved) <= endDate);
}
You will also find this easier to maintain than one huge expression.
Probably this part is your problem:
(profileId != 0 || x.Profile.ProfileID == profileId)
It should be
(profileId == 0 || x.Profile.ProfileID == profileId)
If your profile ID is 0, it will only find entries with x.Profile.ProfileID being 0. Probably there are no such entries.

Return all in List <T> in lambda expression

I'm using lambda expression in LINQ where i have to get all the result when the conditon satisfies if not it should filter.
//Code
List<Dispatch> objDispatch = (List<Dispatch>)Session["Data"];
objDispatch = objDispatch.FindAll(dispatch => dispatch.CustomerTransName == ddlTransporterName.SelectedItem.Text && dispatch.InvoiceDate.Date >= Convert.ToDateTime(FromDate).Date && dispatch.InvoiceDate.Date <= Convert.ToDateTime(ToDate).Date);
In the above code i'm filtering the result set with some conditions in that first condition i need a help.
If the transporter name is 'ALL' it should return all the result set it matches with the Date condition or else it should return according to the TransporterName.
How can i achieve this?
With pure logic.
if(ddlTransporterName.SelectedItem.Text == "ALL") {
//return all
} else {
//Do your filter logic
}
Or, with less repitive code:
objDispatch = objDispatch.FindAll(
dispatch => (ddlTransporterName.SelectedItem.Text == "ALL" || dispatch.CustomerTransName == ddlTransporterName.SelectedItem.Text)
&& dispatch.InvoiceDate.Date >= Convert.ToDateTime(FromDate).Date
&& dispatch.InvoiceDate.Date <= Convert.ToDateTime(ToDate).Date);
string name = ddlTransporterName.SelectedItem.Text;
objDispatch = objDispatch.FindAll(dispatch =>
(name == "ALL" || dispatch.CustomerTransName == name)
&& dispatch.InvoiceDate.Date >= Convert.ToDateTime(FromDate).Date
&& dispatch.InvoiceDate.Date <= Convert.ToDateTime(ToDate).Date);
If transporter name is "ALL" then name OR condition will give true and CustomerTransName will not be checked.
If you want this to be LINQ then you need to actually use a LINQ method e.g. use Where. Also you should do your date conversions once outside if they aren't specific to the row, otherwise they will be converting everytime. Not only that, it makes for more readable code...
var selectedTransporter = ddlTransporterName.SelectedItem.Text;
var fromDate = Convert.ToDateTime(FromDate).Date;
var toDate = Convert.ToDateTime(ToDate).Date;
var query = objDispatch.Where(x => (selectedTransporter == "All" || x.CustomerTransName == selectedTransporter) && x.InvoiceDate.Date >= fromDate && x.InvoiceDate.Date <= toDate);
I think this should suffice:
List<Dispatch> objDispatch = (List<Dispatch>)Session["Data"];
List<Dispatch> filteredDispatches = objDispatch.Where(dispatch => dispatch.InvoiceDate.Date >= Convert.ToDateTime(FromDate).Date && dispatch.InvoiceDate.Date <= Convert.ToDateTime(ToDate).Date).ToList();
if (ddlTransporterName.SelectedItem.Text != "ALL")
{
filteredDispatches = filteredDispatches.Where(dispatch => dispatch.CustomerTransName == ddlTransporterName.SelectedItem.Text).ToList();
}
I think something like this should work:
List<Dispatch> objDispatch = (List<Dispatch>)Session["Data"];
var _fromDate = Convert.ToDateTime(FromDate);
var _toDate = Convert.ToDateTime(ToDate);
objDispatch = objDispatch
.FindAll(dispatch => Selector(
dispatch, ddlTransporterName.SelectedItem.Text, _fromDate, _toDate));
static bool Selector(
Dispatch dispatch, string name, DateTime fromDate, DateTime toDate)
{
if (dispatch.CustomerTransName == "ALL")
{
return dispatch.InvoiceDate.Date >= fromDate.Date
&& dispatch.InvoiceDate.Date <= toDate.Date;
}
return dispatch.CustomerTransName == name;
}

How to use DATEADD over column in LINQ - DateAdd is not recognized by LINQ

I am trying to invalidate requests of friendship that were reponded less than 30 days ago.
var requestIgnored = context.Request
.Where(c => c.IdRequest == result.IdRequest
&& c.IdRequestTypes == 1
&& c.Accepted == false
&& DateTime.Now <= (((DateTime)c.DateResponse).AddDays(30)))
.SingleOrDefault();
c.DateResponse is of type DateTime?. The error I am having is :
LINQ does not recognize the command .AddDays
Edit: If you're using EntityFramework >= 6.0, use DbFunctions.AddDays. For older versions of Entity Framework, use EntityFunctions.AddDays:
var requestIgnored = context.Request
.Where(c => c.IdRequest == result.IdRequest
&& c.IdRequestTypes == 1
&& c.Accepted == false
&& DateTime.Now <= DbFunctions.AddDays(c.DateResponse, 30))
.SingleOrDefault();
You might try this:
var thirtyDaysAgo = DateTime.Now.AddDays(-30);
var requestIgnored = context.Request
.Where(c =>
c.IdRequest == result.IdRequest &&
c.IdRequestTypes == 1 &&
c.Accepted == false &&
c.DateResponse.HasValue &&
thirtyDaysAgo <= c.DateResponse.Value)
.SingleOrDefault();

How to write Linq expression using external objects

I am trying to convert a loop in to a linq expression. But it seams not to work the way i am doing it:
var customer = GetCustomerFromDatabase(id);
ICollection<Order> customerOrders = null;
if (customer == null)
{
LogAndThrowCustomerNotFound(id);
}
else
{
customerOrders = customer.Orders;
}
customer.YearToDateSales = 0.0;
customer.CurrentSales = 0.0;
DateTime today = DateTime.Now;
if (customerOrders != null)
foreach (var order in customerOrders)
{
if (order.SubmittedDate != null
&& order.SubmittedDate.Value.Year.CompareTo(today.Year) == 0)
{
customer.YearToDateSales += (double)order.OrderTotal;
}
if (order.SubmittedDate != null
&& (order.SubmittedDate.Value.Month.CompareTo(today.Month) == 0
&& order.SubmittedDate.Value.Year.CompareTo(today.Year) == 0))
{
customer.CurrentSales += (double)order.OrderTotal;
}
}
So I came up with that expression to get the customer orders that match the current year... bot it does not work. in he expression order is empty and today is conflicting. I i create
DateTime today = DateTime.Now; in the parm of the expression i get different errors...
IEnumerable<Order> cOrders = customerOrders
.Where((ICollection<Order> order , today) =>
order.SubmittedDate.Value.Month == today.Month);
It's simpler if you just don't attempt pass today into the lambda, it'll be closed into the expression anyway;
customer.YearToDateSales = customerOrders
.Where(x => x.SubmittedDate != null &&
x.SubmittedDate.Value.Year == today.Year)
.Sum(x => x.OrderTotal);
customer.CurrentSales = customerOrders
.Where(x => x.SubmittedDate != null &&
x.SubmittedDate.Value.Month == today.Month &&
x.SubmittedDate.Value.Year == today.Year)
.Sum(x => x.OrderTotal);
Hard to tell exactly what's wrong without the error, but you probably need to check for null on the SubmittedDate like in the original version:
IEnumerable<Order> cOrders = customerOrders
.Where((ICollection<Order> order , today) =>
order.SubmittedDate.HasValue &&
order.SubmittedDate.Value.Month == today.Month);

Categories

Resources