Order by with conditions - c#

Try to get this in following order but doesn't work, it does not return the right order, where Cancelled is picked before Unpaid, please let me know
dt = dt.AsEnumerable()
.OrderBy(x => x["TicketStatus"].ToString())
.ThenBy(x => x["TicketStatus"].ToString() == "Attended")
.ThenBy(x => x["TicketStatus"].ToString() == "Issued")
.ThenBy(x => x["TicketStatus"].ToString() == "Unpaid")
.ThenBy(x => x["TicketStatus"].ToString() == "Cancelled")
.GroupBy(x => new {EventID = x["EventID"].ToString(), ContactID = x["ContactID"].ToString()})
.Select(x => x.FirstOrDefault()).CopyToDataTable();

Try something like this
string[] status= { "Attended", "Issued", "Unpaid", "Cancelled" };
var sortstatus = from s in status
orderby s
select s;

just find out this works
List<string> sortOrder = new List<string> { "Attended", "Issued", "Unpaid", "Cancelled" };
dt = dt.AsEnumerable()
.OrderBy(x => sortOrder.IndexOf(x["TicketStatus"].ToString()))
.GroupBy(x => new {EventID = x["EventID"].ToString(), ContactID = x["ContactID"].ToString()})
.Select(x => x.FirstOrDefault()).CopyToDataTable();

Related

How to iterate over a list to build a Linq query

I have the following working query:
posts.Where(post =>
post.Fields
.Where(x =>
x.RegionId == "RecipeArticleDetails" &&
(x.FieldId == "RecipePrepTime" || x.FieldId == "RecipeCookTime")
)
.GroupBy(x => x.PostId)
.Select(x => new { ID = x.Key, Value = x.Sum(y => Convert.ToInt32(y.Value)) })
.Where(x => x.Value > 10 && x.Value < 40)
.Any()
)
List<string> suppliedTimes = new List<string>(){
"10-60","0-10"
};
I would like to replace Where(x => x.Value > 10 && x.Value < 40) so it looks up from a list of ranges:
List<string> suppliedTimes = new List<string>(){
"10-60","0-10"
};
My understanding is I can use select to iterate over the items:
posts.Where(post =>
suppliedTimes.Select(x => new {low = Convert.ToInt32(x.Split("-",StringSplitOptions.RemoveEmptyEntries)[0]), high = Convert.ToInt32(x.Split("-",StringSplitOptions.RemoveEmptyEntries)[1]) })
.Any( a =>
post.Fields
.Where(x =>
x.RegionId == "RecipeArticleDetails" &&
(x.FieldId == "RecipePrepTime" || x.FieldId == "RecipeCookTime")
)
.GroupBy(x => x.PostId)
.Select(x => new { ID = x.Key, Value = x.Sum(y => Convert.ToInt32(y.Value)) })
.Where(x => x.Value > a.low && x.Value < a.high)
.Any()
)
)
However this code results in the error:
could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
Please can someone explain how I can achieve this and why what I have isn't working.
To make it work with EF Core I would suggest my extnsion FilterByItems and change the way how to retrieve records.
List<string> suppliedTimes = new List<string>(){
"10-60","0-10"
};
var ranges = suppliedTimes
.Select(x => x.Split("-", StringSplitOptions.RemoveEmptyEntries))
.Select(x => new {
low = Convert.ToInt32(x[0]),
high = Convert.ToInt32(x[1])
});
var fields = context.Fields
.Where(x =>
x.RegionId == "RecipeArticleDetails" &&
(x.FieldId == "RecipePrepTime" || x.FieldId == "RecipeCookTime")
)
.GroupBy(x => x.PostId)
.Select(x => new { ID = x.Key, Value = x.Sum(y => Convert.ToInt32(y.Value)) })
.FilterByItems(ranges, (e, r) => e.Value > r.low && e.Value < r.high, true);
var posts = posts
.Join(fields, p => p.Id, f => f.ID, (p, f) => p);

Return additional column in Linq Query?

I have this Linq query:
var area = db.MyDbSet
.Where(s => s.langid == langid)
.GroupBy(s => s.Title)
.Select(g => new { Title = g.Key })
.Select(s => s.Title);
I want to return another column from the same table, its called: CodeId.
I am noob Linq programmer and quite lost in all those mish-mash things in C# so I can't really understand what should I do.
Can somebody help me how to return the another column from the same table with the same query call?
This may help you :
var area = db.MyDbSet
.Where(s => s.langid == langid)
.GroupBy(s => s.Title)
.Select(g => new { Title = g.Key, CodeId = g.FirstOrDefault().CodeId });
var area = db.MyDbSet
.Where(s => s.langid == langid)
.GroupBy(s => s.Title)
.Select(g => new {
Title = g.Key,
CodeId = g.Id,
OtherField = "Field"
})

Linq - Get Max date from resultset

I need to convert the following SQL query to Linq :-
SELECT CODE,SCODE,MAX(SDATE) AS SDATE FROM SHIFTSCHEDULE
WHERE COMPANY = 'ABC'
GROUP BY CODE,SCODE
ORDER BY MAX(SDATE)
DESC
So far, I have tried this :-
var data = ctx.ShiftSchedule.Where(m =>
m.Company == company && m.EmployeeId == item.EmployeeId
)
.GroupBy(m =>
new
{
m.EmployeeId,
m.ShiftId
})
.Select(m =>
new
{
EmployeeId = m.Key.EmployeeId,
ShiftCode = m.Key.ShiftId,
ShiftDate = m.Max(gg => gg.ShiftDate)
}).ToList();
The results i get are :-
Now what i want is to get record or item in this result set which is MaxDate. In the above image the MaxDate is 1st record.
How to get the MAXDATE from the resultset?
This should work:-
var data = ctx.ShiftSchedule.Where(x => x.Company == company
&& x.EmployeeId == item.EmployeeId)
.GroupBy(x => new { x.CODE, x.SCODE })
.Select(x => new
{
CODE = x.Key.CODE,
SCODE = x.Key.SCODE,
SDATE = x.Max(z => z.SDATE)
})
.OrderByDescending(x => x.SDATE).FirstOrDefault();
You can order the resulting collection and fetch the first object using FirstOrDefault.
If you want just MAXDATE, you can only project that.
Just add .OrderByDescending(x => x.ShiftDate).First(); at the end.
OrderByDescending date and then take .First()
var data = ctx.ShiftSchedule.Where(m =>
m.Company == company && m.EmployeeId == item.EmployeeId
)
.GroupBy(m =>
new
{
m.EmployeeId,
m.ShiftId
})
.Select(m =>
new
{
EmployeeId = m.Key.EmployeeId,
ShiftCode = m.Key.ShiftId,
ShiftDate = m.Max(gg => gg.ShiftDate)
}).ToList().OrderByDescending(x => x.ShiftDate).First();

How to find `Distinct` records in LINQ?

I want to find distinct records in entity framework. My code is as below
var distinctYear = _objCalRepos
.GetDetails()
.Select(o => new CalendarList { Mdate = o.Mdate.Year.ToString() })
.Distinct()
.ToList();
ddlYear.DataSource = distinctYear;
ddlYear.DataTextField = "Mdate";
ddlYear.DataValueField = "Mdate";
ddlYear.DataBind();
Here Distinct not works. It will return all entries(duplicated).
Distinct is not working, probably because CalendarList is not comparable.
Try this:
var distinctYear = _objCalRepos
.GetDetails()
.Select(o => o.Mdate.Year.ToString())
.Distinct()
.AsEnumerable()
.Select(o => new CalendarList { Mdate = o }))
.ToList();
You can use GroupBy
var distinctYear = _objCalRepos
.GetDetails()
.Select(o => new CalendarList { Mdate = o.Mdate.Year.ToString() })
.GroupBy(cl => cl.Mdate )
.Select(g => g.First())
.ToList();

Adding more parameters to a Linq query

I'm using this query to count number of orders by date. I'm trying to add one more parameter that counts total products for each order, however I can't get it to work atm.
This is the essential part of a method that is suposed to return a list of 3 parameters (Date, TotalOrders and TotalProducts). Im using a Linq query to get a list with total order for each date, im wondering how to add my third parameter to the list "TotalProducts" and if i can do by adding one more search parameter in the Query. The foreach part below do not work propertly, it will return a list of TotalProducts but CreationDate will be the same for ech item in the list. I also have a feeling putting a foreach inside a foreach dosn't seem optimal for this:
var orders = _orderService.SearchOrderStatistics(startDateValue, endDateValue, orderStatus,
paymentStatus, shippingStatus, model.CustomerEmail, model.OrderGuid);
var result = orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new { Date = s.Key, Count = s.Count() });
List<GCOrdersModel> TotalOrdersPaid = new List<GCOrdersModel>();
foreach (var g in result)
{
foreach (var opv in orders)
{
GCOrdersModel _Om = new GCOrdersModel(g.Date, g.Count.ToString(), opv.OrderProductVariants.Count.ToString());
TotalOrdersPaid.Add(_Om);
}
}
return TotalOrdersPaid;
To access total products for every orders I must use OrderProductVariants.Count.ToString()
Can I add this parameter to the query?
Thx
You could try this:
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel()
{
Date = s.Key,
Count = s.Count(),
OpvCount = opv.OrderProductVariants.Count.ToString()
})
.ToList();
or
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel(s.Key, s.Count, opv.OrderProductVariants.Count.ToString()))
.ToList();
That way, you don't have to iterate over your result again. And it automatically creates your list of GCOrdersModel.
Edit
Does this work?
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel()
{
Date = s.Key,
Count = s.Count(),
OpvCount = s.OrderProductVariants.Count.ToString()
})
.ToList();
or
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel(s.Key, s.Count(), s.OrderProductVariants.Count.ToString()))
.ToList();
How about:
var opvCount =
opv
.OrderProductVariants
.Count
.ToString();
return
orders
.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new
{
Date = s.Key,
Count = s.Count()
})
.Select(x =>
new GCOrdersModelg(x.Date, g.Count.ToString(), opvCount));

Categories