LINQ Additional Filter in Select Statement - sql-server

I am unfamiliar with LINQ and I am trying to modify an existing query.
Below is the code snippet and the filter that I would like to add in:
ViewData["Employees"] = emps = (from staff in db.Staffs
from jobinfo in db.JobInfo
.Where(x => x.staff_id == staff.StaffID)
.OrderByDescending(x => x.jobinfo_id).Take(1)
select new { staff, jobinfo })
.Select(x => x.staff).Distinct().OrderBy(x => x.Alias).ToList();
*** Insert Additional filter at the .Select statement above
<where (jobinfo.last_date == null)>
May I know how can it be done?

Could you please try like below and check in the third line?
.Where(x => x.staff_id == staff.StaffID && x.last_date == null)

two options one is to use && and use another where as follows
ViewData["Employees"] = emps = (from staff in db.Staffs
from jobinfo in db.JobInfo
.Where((x => x.staff_id == staff.StaffID) && (jobinfo.last_date == null))
.OrderByDescending(x => x.jobinfo_id).Take(1)
select new { staff, jobinfo })
.Select(x => x.staff).Distinct().OrderBy(x => x.Alias).ToList();
Other options would be
ViewData["Employees"] = emps = (from staff in db.Staffs
from jobinfo in db.JobInfo
.Where((x => x.staff_id == staff.StaffID)).Where(jobinfo.last_date == null)
.OrderByDescending(x => x.jobinfo_id).Take(1)
select new { staff, jobinfo })
.Select(x => x.staff).Distinct().OrderBy(x => x.Alias).ToList();

Related

Insert Additional Condition in LINQ

I am modifying a LINQ query in SQL Server 2014, but I have never used the syntax:
if (!UserAccessMatrixSession.HasRole(Session, Constant.ROLE_STAFF))
{
if (country != 0 )
{
ViewData["Employees"] = (from staff in db.Staffs
from jobinfo in db.JobInfo
.Where(x => x.staff_id == staff.StaffID)
.OrderByDescending(x => x.jobinfo_id).Take(1)
orderby staff.Alias
select new { staff, jobinfo }).Where(x => x.jobinfo.location == country)
.Select(x => x.staff).ToList();
}
else
{
ViewData["Employees"] = (from staff in db.Staffs
orderby staff.Alias
select staff).ToList();
}
}
I would like to insert an additional condition as follows:
where jobinfo.last_date == null OR DateTime.Now < jobinfo.last_date
I believe you would want to add that where clause into where you are selecting from the job info
if (!UserAccessMatrixSession.HasRole(Session, Constant.ROLE_STAFF))
{
if (country != 0 )
{
ViewData["Employees"] = (from staff in db.Staffs
from jobinfo in db.JobInfo
.Where(x => x.staff_id == staff.StaffID)
.OrderByDescending(x => x.jobinfo_id).Take(1)
orderby staff.Alias
select new { staff, jobinfo }).Where(x => x.jobinfo.location == country
/* last_date null or UtcNow < last_date*/ && (x.jobinfo.last_date == null || DateTime.UtcNow < jobinfo.last_date))
.Select(x => x.staff).ToList();
}
else
{
ViewData["Employees"] = (from staff in db.Staffs
orderby staff.Alias
select staff).ToList();
}
}

EF optimize multiple order by select top 1

I have the following Entity Framework query:
var queryResponse = await db.DataPoints.GroupBy(x => x.Device).Select(x => new
{
lon = x.Key.DataPoints.OrderByDescending(y => y.DateTime).Select(y => y.Longitude).FirstOrDefault(),
lat = x.Key.DataPoints.OrderByDescending(y => y.DateTime).Select(y => y.Longitude).FirstOrDefault(),
date = x.Key.DataPoints.OrderByDescending(y => y.DateTime).Select(y => y.DateTime).FirstOrDefault(),
label = x.Key.Name,
})
.OrderByDescending(x => x.label)
.ToListAsync();
Now you can see in my select, I have to get lon,'lat', and 'date'. However the way im doing it, I have to orderby and select the first one 3 times. The 'DataPoints' is a very large table.
in C# i would normally do the orderBy once and just select the entire object, and then later on break it up into the 3 properties. However in this case I want SQL to return the exact fields.
is there a more efective way to write this query?
Try this:
var queryResponse =
(from g in db.DataPoints.GroupBy(x => x.Device)
let latestDataPoint = g.Key.DataPoints.OrderByDescending(p => p.DateTime)
.FirstOrDefault()
select new
{
lon = latestDataPoint.Longitude,
lat = latestDataPoint.Latitude,
date = latestDataPoint.DateTime,
label = g.Key.Name
})
.OrderByDescending(x => x.label)
.ToList();

Converting SQL Server query containing GROUP BY into NHibernate LINQ

I'm basically trying to retrieve a paged list of unique GUIDs, sorted by (row) creation date.
I've been able to draft a SQL Server query that seems to work for me based on this answer, but now I have to translate that into LINQ.
SELECT TOP 15 payment.ClientRef,
MAX(payment.CreatedDateUtc)
FROM PaymentTransactionState payment
INNER JOIN OrderState orderstate ON payment.ClientRef = orderstate.ClientRef
WHERE orderstate.UserId = 2 AND
payment.PaymentState IN (
'Rejected',
'Authorized')
GROUP BY payment.ClientRef
ORDER BY MAX(payment.CreatedDateUtc) DESC,
payment.ClientRef
Problem is, I can't apply GroupBy on an IQueryOver, I'm probably missing the appropiate syntax:
session
.QueryOver<Payment>()
.JoinAlias(orderState => orderState.OrderStateEntity, () => orderStateRow)
.Where(() => orderStateRow.UserId == customer.UserId)
.WhereRestrictionOn(payment => payment.PaymentState).IsIn(paymentStates)
.GroupBy(pts => pts.ClientRef)
.OrderBy(payment => payment.CreatedDateUtc).Desc
.Skip(pageIndex*pageSize)
.Take(pageSize)
.List();
I could probably do the group by in query syntax, but I'm not so sure about the Skip & Take bit.
I would try like this:
var query = db.PaymentTransactionState
.Where( pts => pts.OrderState.UserId == 2 &&
new string[] {"Rejected", "Authorized"}.Contains(pts.PaymentState) )
.GroupBy( pts => pts.ClientRef )
.OrderByDescending( pts => pts.Max( p => p.CreatedDateUtc))
.ThenBy( p => p.Key )
.Take(15);
So here's what worked for me: basically I had to use SelectList instead of GroupBy; SelectGroup, SelectMax & TransformUsing were easy to tackle once I found that;
PaymentRow paymentAlias = null;
OrderStateRow orderStateRow = null;
var transactionStateRows = session
.QueryOver<PaymentRow >()
.JoinAlias(orderState => orderState.OrderStateEntity, () => orderStateRow)
.Where(() => orderStateRow.UserId == customer.UserId)
.WhereRestrictionOn(payment => payment.PaymentState).IsIn(paymentStates)
.SelectList(list => list
.SelectGroup(payment => payment.ClientRef).WithAlias(() => paymentAlias.ClientRef)
.SelectMax(payment => payment.CreatedDateUtc).WithAlias(() => paymentAlias.CreatedDateUtc))
.TransformUsing(Transformers.AliasToBean<PaymentRow >())
.OrderBy(payment => payment.CreatedDateUtc).Desc
.Skip(pageIndex*pageSize)
.Take(pageSize)
.List();
I'll leave this here in case someone might find my travails useful in the future. Thank you for your replies.

Query Slow in Linq, Fast in LinqPad, SQL Management Studio and SQL Profiler

I have this linq query i'm using and it's taking 50 seconds to run when i am running it my asp.net application, however the same query executes in 500ms in LinqPad and Sql Management Studio.
I even took the query from the SQL Profiler and ran it again in SQL Management Studio and it takes around 500ms. What overhead Linq could be doing, that an extra 49s??
Below is the code for reference, thanks for your help.
var rCampaign =
(from a in db.AdCreative
join h in db.AdHit on a.ID equals h.AdID into gh
join l in db.AdGroup_Location on a.AdGroupID equals l.AdGroupID into gj
from subloc in gj.DefaultIfEmpty()
from subhits in gh.DefaultIfEmpty()
where a.AdGroup.AdHost.Select(q => q.ID).Contains(rPlatform.ID) &&
a.AdGroup.AdPublisher.Select(q => q.ID).Contains(rPublisher.ID) &&
a.AdDimensionID == AdSize &&
a.AdGroup.Campaign.Starts <= rNow &&
a.AdGroup.Campaign.Ends >= rNow &&
subhits.HitType == 1 &&
(subloc == null || subloc.LocationID == rLocationID)
select new {
ID = a.ID,
Name = a.Name,
Spent = (subhits.AdDimension != null) ? ((double)subhits.AdDimension.Credit / 1000) : 0,
CampaignID = a.AdGroup.Campaign.ID,
CampaignName = a.AdGroup.Campaign.Name,
CampaignBudget = a.AdGroup.Campaign.DailyBudget
}).GroupBy(adgroup => adgroup.ID)
.Select(adgroup => new {
ID = adgroup.Key,
Name = adgroup.FirstOrDefault().Name,
Spent = adgroup.Sum(q => q.Spent),
CampaignID = adgroup.FirstOrDefault().CampaignID,
CampaignName = adgroup.FirstOrDefault().CampaignName,
CampaignBudget = adgroup.FirstOrDefault().CampaignBudget,
})
.GroupBy(q => q.CampaignID)
.Select(campaigngroup => new {
CampaignID = campaigngroup.Key,
DailyBudget = campaigngroup.FirstOrDefault().CampaignBudget,
Consumed = campaigngroup.Sum(q => q.Spent),
RemainningCredit = campaigngroup.FirstOrDefault().CampaignBudget - campaigngroup.Sum(q => q.Spent),
Ads = campaigngroup.Select(ag => new {
ID = ag.ID,
Name = ag.Name,
Spent = ag.Spent
}).OrderBy(q => q.Spent)
})
.Where(q => q.Consumed <= q.DailyBudget).OrderByDescending(q => q.RemainningCredit).First();
There are a few ways you can simplify that query:
select into lets you keep it all in query syntax.
The join ... into/from/DefaultIfMany constructs implementing left joins can be replaced with join ... into construcs representing group joins.
Some of the groups near the end cannot be empty, so FirstOrDefault is unnecessary.
Some of the where conditions can be moved up to the top before the query gets complicated.
Here's the stab I took at it. The revisions were significant, so it might need a little debugging:
var rCampaign = (
from a in db.AdCreative
where a.AdDimensionID == AdSize &&
a.AdGroup.Campaign.Starts <= rNow &&
a.AdGroup.Campaign.Ends >= rNow &&
a.AdGroup.AdHost.Select(q => q.ID).Contains(rPlatform.ID) &&
a.AdGroup.AdPublisher.Select(q => q.ID).Contains(rPublisher.ID)
join hit in db.AdHit.Where(h => h.HitType == 1 && h.LocationID == rLocationID)
on a.ID equals hit.AdID
into hits
join loc in db.AdGroup_Location
on a.AdGroupID equals loc.AdGroupID
into locs
where !locs.Any() || locs.Any(l => l.LocationID == rLocationID)
select new {
a.ID,
a.Name,
Spent = hits.Sum(h => h.AdDimension.Credit / 1000) ?? 0,
CampaignID = a.AdGroup.Campaign.ID,
CampaignName = a.AdGroup.Campaign.Name,
CampaignBudget = a.AdGroup.Campaign.DailyBudget,
} into adgroup
group adgroup by adgroup.CampaignID into campaigngroup
select new
{
CampaignID = campaigngroup.Key,
DailyBudget = campaigngroup.First().CampaignBudget,
Consumed = campaigngroup.Sum(q => q.Spent),
RemainingCredit = campaigngroup.First().CampaignBudget - campaigngroup.Sum(q => q.Spent),
Ads = campaigngroup.Select(ag => new {
ag.ID,
ag.Name,
ag.Spent,
}).OrderBy(q => q.Spent)
} into q
where q.Consumed <= q.DailyBudget
orderby q.RemainingCredit desc)
.First()
I refactored using Query syntax (Not sure if it improved readability). Removed one group by. Made some minor adjustments (replaced FirstOrDefault with Key property, changed Contains to Any). Hopefully it has some effect of speed.
var rCampaign = (from cg in
(from a in db.AdCreative
from subhits in db.AdHit.Where(h => a.ID == h.AdID)
.DefaultIfEmpty()
from subloc in db.AdGroup_Location.Where(l => a.AdGroupID == l.AdGroupID)
.DefaultIfEmpty()
where a.AdGroup.AdHost.Any(q => q.ID == rPlatform.ID) &&
a.AdGroup.AdPublisher.Any(q => q.ID == rPublisher.ID) &&
a.AdDimensionID == AdSize &&
a.AdGroup.Campaign.Starts <= rNow &&
a.AdGroup.Campaign.Ends >= rNow &&
subhits.HitType == 1 &&
(subloc == null || subloc.LocationID == rLocationID)
group new { a, subhits } by new { ID = a.ID, a.Name, CampaignID = a.AdGroup.Campaign.ID, CampaignName = a.AdGroup.Campaign.Name, CampaignBudget = a.AdGroup.Campaign.DailyBudget } into g
select new
{
ID = g.Key.ID,
Name = g.Key.Name,
Spent = g.Sum(x => (x.subhits.AdDimension != null) ? ((double)subhits.AdDimension.Credit / 1000) : 0),
CampaignID = g.Key.CampaignID,
CampaignName = g.Key.CampaignName,
CampaignBudget = g.Key.CampaignBudget
})
group cg by new { cg.CampaignID, cg.CampaignBudget } into cg
let tempConsumed = cg.Sum(q => q.Spent)
let tempRemainningCredit = cg.Key.CampaignBudget - tempConsumed
where tempConsumed <= cg.Key.CampaignBudget
orderby tempRemainningCredit desc
select new
{
CampaignID = cg.Key.CampaignID,
DailyBudget = cg.Key.CampaignBudget,
Consumed = tempConsumed,
RemainningCredit = tempRemainningCredit,
Ads = from ag in cg
orderby ag.Spent
select new
{
ID = ag.ID,
Name = ag.Name,
Spent = ag.Spent
}
}).First();

Subsonic 3.0 UPDATE, multiple conditions

db.Update<Luna.Record.TB_ITEM>().Set(
x => x.ITEM_DURABILITY == Convert.ToInt32(quantity))
.Where(x => x.ITEM_POSITION == Convert.ToInt32(position))
.Execute();
How will I add an AND clause this is how it looks like in plain SQL:
UPDATE TB_ITEM
SET ITEM_DURABITLITY=#quantity
WHERE ITEM_POSITION=#position AND CHARACTER_IDX=#charidx
.Where(x => x.ITEM_POSITION == Convert.ToInt32(position)
&& x.CHARACTER_IDX == Convert.ToInt32(charidx))

Resources