Convert query to lambda - linq

I want to know how can I write this query:
var query = from p in context.DimProduct
from psc in context.DimProductSubcategory
// on psc.ProductCategoryKey equals pc.ProductCategoryKey
where psc.EnglishProductSubcategoryName == subCategoryName
&& psc.ProductSubcategoryKey == p.ProductSubcategoryKey
select new DimProductDTO
{
ProductKey = p.ProductKey,
ProductSubcategoryKey = p.ProductSubcategoryKey,
EnglishProductName = p.EnglishProductName,
Size = p.Size,
StandardCost = p.StandardCost
};
I tried some queries, but no success. My problem is that I don't know how to have access to DimProduct and DimProductSubcategory.
Any suggestions?

context.DimProduct
.SelectMany(p => new { p, psc = context.DimProductSubcategory })
.Where(x => x.psc.EnglishProductSubcategoryName == subCategoryName
&& x.psc.ProductSubcategoryKey == x.p.ProductSubcategoryKey)
.Select(x => new DimProductDTO {
ProductKey = x.p.ProductKey,
ProductSubcategoryKey = x.p.ProductSubcategoryKey,
EnglishProductName = x.p.EnglishProductName,
Size = x.p.Size,
StandardCost = x.p.StandardCost })
However, you're not selecting anything from DimProductSubcategory, so I think the same can be done using Any() extension method:
context.DimProduct
.Where(x => context.DimProductSubcategory
.Any(y => y.EnglishProductSubcategoryName == subCategoryName
&& y.ProductSubcategoryKey == x.ProductSubcategoryKey))
.Select(x => new DimProductDTO {
ProductKey = x.ProductKey,
ProductSubcategoryKey = x.ProductSubcategoryKey,
EnglishProductName = x.EnglishProductName,
Size = x.Size,
StandardCost = x.StandardCost });
It should generate IN SQL statement within the query.

That is not exactly same query, but it produces same result via inner join (I believe that is more efficient than cross join)
context.DimProduct
.Join(context.DimProductSubcategory
.Where(x => x.EnglishProductSubcategoryName == subCategoryName),
p => ProductSubcategoryKey,
psc => ProductSubcategoryKey,
(p,psc) => new { p, psc })
.Select(x => new DimProductDTO {
ProductKey = x.p.ProductKey,
ProductSubcategoryKey = x.p.ProductSubcategoryKey,
EnglishProductName = x.p.EnglishProductName,
Size = x.p.Size,
StandardCost = x.p.StandardCost })
Also your original query can be rewritten as
var query = from p in context.DimProduct
join psc in context.DimProductSubcategory
on p.ProductSubcategoryKey equals psc.ProductSubcategoryKey
where psc.EnglishProductSubcategoryName == subCategoryName
select new DimProductDTO {
ProductKey = p.ProductKey,
ProductSubcategoryKey = p.ProductSubcategoryKey,
EnglishProductName = p.EnglishProductName,
Size = p.Size,
StandardCost = p.StandardCost
};
Generated SQL will look like:
SELECT [t0].[ProductKey], [t0].[ProductSubcategoryKey]
FROM [DimProduct] AS [t0]
INNER JOIN [DimProductSubcategory] AS [t1]
ON [t0].[EnglishProductSubcategoryName] = [t1].[ProductSubcategoryKey]
WHERE [t1].[EnglishProductSubcategoryName] = #p0

Related

How to do a cascading IGrouping?

I'm trying to do a cascading groupby, but I can't find a way to get the proper index in the end (the .ElementAt(0) in the end of the code is wrong, in all 3 levels of hierarchy).
//Level
//---|Category
//---|---|Family
//---|---|---|Type
//---|---|---|---|Leaf
var leafs = queryLeafs.ToList();
foreach (var leaf in leafs)
{
//Get Type
var leafAttr = leaf.ObjectsEav.First(eav => eav.Attribute.Name == "parent");
long typeId = leafAttr.Value.Value;
leaf.Type = universe.First(o => o.Id == typeId);
//Family
var typeAttr = leaf.Type.ObjectsEav.First(eav => eav.Attribute.Name == "parent");
long familyId = typeAttr.Value.Value;
leaf.Family = universe.First(o => o.Id == familyId);
//Category
var familyAttr = leaf.Family.ObjectsEav.First(eav => eav.Attribute.Name == "parent");
long categoryId = familyAttr.Value.Value;
leaf.Category = universe.First(o => o.Id == categoryId);
}
var groupType = leafs.GroupBy(leaf => leaf.Type);
var groupFamily = groupType.GroupBy(t => **t.ElementAt(0)**.Family);
var groupCategory = groupFamily.GroupBy(f => **f.ElementAt(0).ElementAt(0)**.Category);
Can someone provide a light in my dark path?
If you have any suggestion on how to improve this question, I would appreciate with all my heart.

converting a sql server view to linq

I'm not sure if this is the right forum, if not please move it
My office is in the process of re-writing our app and switching from VB to C# and the entity framework. I've had some success in joining multiple tables all with left outer joins but I'm at my limits on how to convert an sql view like the following:
SELECT dbo.Addresses.AddressId, dbo.AddressTypes.AddressType, dbo.Addresses.AddressTypeId, dbo.Addresses.ParentAddressId, dbo.Addresses.AddressCode, dbo.Addresses.AddressNumber, dbo.Addresses.Address,
dbo.Addresses.SubAddress, dbo.Addresses.Direction, dbo.Addresses.City, dbo.Addresses.StateId, dbo.Addresses.CountryId, ISNULL(dbo.Addresses.AddressNumber + ' ', '') + ISNULL(dbo.Addresses.Direction + ' ', '')
+ ISNULL(dbo.Addresses.Address + ' ', '') + ISNULL(dbo.Addresses.Suffix + ' ', '') + ISNULL(dbo.Addresses.SubAddress + ' ', '') AS FullAddress, dbo.Addresses.RegionId, dbo.Addresses.CountyId,
dbo.Addresses.OccupancyTypeId, dbo.Addresses.PropertyUseTypeId, dbo.Addresses.Comment, dbo.States.StateAbbr, dbo.States.State, dbo.Regions.Region, dbo.Regions.RegionCode, dbo.Counties.County,
dbo.Counties.CountyCode, dbo.Countries.Country, dbo.OccupancyTypes.OccupancyType, dbo.OccupancyTypes.OccupancyTypeCode, dbo.PropertyUseTypes.PropertyUseType, dbo.Party.PartyName,
dbo.PropertyUseTypes.PropertyUseTypeCode, dbo.UserDefFields.UserDefFieldId, dbo.UserDefFields.FieldDesc, dbo.UserDefValues.UserDefValueId, dbo.UserDefValues.UserDefValue, dbo.Addresses.ZipId, dbo.Zips.Zip,
dbo.AddressParties.PartyID, dbo.Addresses.Latitude, dbo.Addresses.Longitude, dbo.Addresses.Inactive, dbo.Addresses.DefaultPass, dbo.Addresses.Suffix, dbo.AddressTypes.AgencyId, dbo.Addresses.LegalDesc,
dbo.AddressParties.Inactive AS PAInactive, dbo.AddressParties.RoleTypeId, dbo.Addresses.POBox, dbo.AddressParties.ExternalValue, dbo.Addresses.DateUpdated, dbo.Addresses.DateInserted, dbo.Addresses.ReportId,
dbo.Addresses.Map, dbo.Addresses.Block, dbo.Addresses.Lot, dbo.Addresses.TaxParcel, dbo.Addresses.ExternalId, dbo.Addresses.Schedule
FROM dbo.UserDefFields RIGHT OUTER JOIN
dbo.UserDefValues ON dbo.UserDefFields.UserDefFieldId = dbo.UserDefValues.UserDefFieldId RIGHT OUTER JOIN
dbo.Party RIGHT OUTER JOIN
dbo.Addresses LEFT OUTER JOIN
dbo.Zips ON dbo.Addresses.ZipId = dbo.Zips.ZipId LEFT OUTER JOIN
dbo.AddressTypes ON dbo.Addresses.AddressTypeId = dbo.AddressTypes.AddressTypeId LEFT OUTER JOIN
dbo.States ON dbo.Addresses.StateId = dbo.States.StateId LEFT OUTER JOIN
dbo.Regions ON dbo.Addresses.RegionId = dbo.Regions.RegionId LEFT OUTER JOIN
dbo.Counties ON dbo.Addresses.CountyId = dbo.Counties.CountyId LEFT OUTER JOIN
dbo.Countries ON dbo.Addresses.CountryId = dbo.Countries.CountryId LEFT OUTER JOIN
dbo.OccupancyTypes ON dbo.Addresses.OccupancyTypeId = dbo.OccupancyTypes.OccupancyTypeId LEFT OUTER JOIN
dbo.PropertyUseTypes ON dbo.Addresses.PropertyUseTypeId = dbo.PropertyUseTypes.PropertyUseTypeId LEFT OUTER JOIN
dbo.AddressParties ON dbo.Addresses.AddressId = dbo.AddressParties.AddressID ON dbo.Party.PartyID = dbo.AddressParties.PartyID ON dbo.UserDefValues.RecordId = dbo.Addresses.AddressId
Into something like the following:
public List<AddressPartyList> GetAddressPartyList(Guid? AddressId, Guid? RoleTypeId = null, bool ShowInactive = false, bool FromWebOnly = false, bool WebAcceptedOnly = false, bool WebRejectedOnly = false)
{
IQueryable<AddressPartyList> thisList;
thisList = myappContext.myappData().AddressParties.Join(
myappContext.myappData().RoleTypes, ap => ap.RoleTypeId, rt => rt.RoleTypeId, (ap, rt) => new { ap, rt }).Join(
myappContext.myappData().Parties, apr => apr.ap.PartyId, p => p.PartyId, (apr, p) => new AddressPartyList
{
AddressId = apr.ap.AddressId,
PartyId = apr.ap.PartyId,
AccountId = p.AccountId,
RoleType = apr.rt.RoleType1,
Salutation = p.Salutation,
FirstName = p.FirstName,
MiddleInitial = p.MiddleInitial,
LastName = p.LastName,
Suffix = p.Suffix,
PartyName = p.PartyName,
Email = p.Email,
Comment = p.Comment,
ExternalId = p.ExternalId,
PartyInactive = p.Inactive,
WebAccountId = p.WebAccountId,
DateUpdated = p.DateUpdated,
DateInserted = p.DateInserted,
PriceLevel = p.PriceLevel,
FromWeb = p.FromWeb,
WebAccepted = p.WebAccepted,
WebRejected = p.WebRejected,
RoleTypeId = apr.ap.RoleTypeId,
InactiveAtAddress = apr.ap.Inactive,
IsBus = p.IsBus,
Sequence = apr.ap.Sequence,
AddressPartyId = apr.ap.AddressPartyId
}).Where(p => p.AddressId == AddressId);
if (!ShowInactive)
{
thisList = thisList.Where(p => p.PartyInactive == false && p.InactiveAtAddress == false);
}
if (RoleTypeId != null)
{
thisList = thisList.Where(p => p.RoleTypeId == RoleTypeId);
}
if (FromWebOnly)
{
thisList = thisList.Where(p => p.FromWeb == true);
}
if (WebAcceptedOnly)
{
thisList = thisList.Where(p => p.WebAccepted == true);
}
if (WebRejectedOnly)
{
thisList = thisList.Where(p => p.WebRejected == true);
}
return thisList.GroupBy(p => p.PartyId).Select(p => p.FirstOrDefault()).OrderBy(p => p.Sequence).ThenBy(p => p.PartyName).ToList();
}
Any help would be appreciated. Also, what would be the syntax for a view with multiple right and left outer joins. I didn't code it, I'm just trying to convert it and I understand it's best to use left outer joins.
Thanks.

linq sum of multiple values

i need to get the sum of billableHours and nonBillableHours.
this is my code.
var currentMonth = 10;
var userQuery =
from timeEntry in TimeEntries
join ta in Tasks on timeEntry.TaskID equals ta.TaskID
where timeEntry.DateEntity.Month == currentMonth && timeEntry.DateEntity.Year == DateTime.Today.Year
select new
{
HoursEntered = timeEntry.HoursEntered,
Billable = ta.Billable
};
var localrows = userQuery.ToList();
var grouping = localrows.GroupBy(x => x.Billable);
var userList = grouping.Select(q => new
{
billableHours = q.Where(x=> x.Billable == true),
nonBillableHours = q.Where(x=> x.Billable != true)
});
i cannot seem to find a way to get the sum.
I need the sum of those two columns, so i can call them,
and calculate values i get from them.
When you need more than one aggregate, you can still get the result with a single query by using group by constant technique. Which in this specific case can be combined with conditional Sum:
var hoursInfo =
(from timeEntry in TimeEntries
join ta in Tasks on timeEntry.TaskID equals ta.TaskID
where timeEntry.DateEntity.Month == currentMonth && timeEntry.DateEntity.Year == DateTime.Today.Year
group new { timeEntry.HoursEntered, ta.Billable } by 1 into g
select new
{
BillableHours = g.Sum(e => e.Billable ? e.HoursEntered : 0),
NonBillableHours = g.Sum(e => !e.Billable ? e.HoursEntered : 0),
}).FirstOrDefault();
You do not need to group them. Try this query:
var userQuery =
from timeEntry in TimeEntries
join ta in Tasks on timeEntry.TaskID equals ta.TaskID
where timeEntry.DateEntity.Month == currentMonth
&& timeEntry.DateEntity.Year == DateTime.Today.Year
select new
{
HoursEntered = timeEntry.HoursEntered,
Billable = ta.Billable
};
var billableHours = userQuery
.Where(m => m.Billable) // Billable
.Select(m => m.HoursEntered)
.DefaultIfEmpty(0)
.Sum();
var nonBillableHours = userQuery
.Where(m => !m.Billable) // Non-bilable
.Select(m => m.HoursEntered)
.DefaultIfEmpty(0)
.Sum();
var currentMonth = 10;
var TimeEntries = new List<TimeEntry>() {
new TimeEntry(){TaskID = 1,DateEntity = DateTime.Now.AddDays(1),HoursEntered =2},
new TimeEntry(){TaskID = 2,DateEntity = DateTime.Now.AddDays(2),HoursEntered =3},
new TimeEntry(){TaskID = 3,DateEntity = DateTime.Now.AddDays(3),HoursEntered =2},
new TimeEntry(){TaskID = 4,DateEntity = DateTime.Now.AddDays(4),HoursEntered =4},
new TimeEntry(){TaskID = 5,DateEntity = DateTime.Now.AddDays(5),HoursEntered =2},
new TimeEntry(){TaskID = 6,DateEntity = DateTime.Now.AddDays(6),HoursEntered =6}
};
var UserTasks = new List<UserTask>(){
new UserTask(){TaskID = 1,Billable = true} ,
new UserTask(){TaskID = 2,Billable = false} ,
new UserTask(){TaskID = 3,Billable = true} ,
new UserTask(){TaskID = 4,Billable = false} ,
new UserTask(){TaskID = 5,Billable = true} ,
new UserTask(){TaskID = 6,Billable = false}
};
var userQuery =
from x in
(from timeEntry in TimeEntries
join ta in UserTasks on timeEntry.TaskID equals ta.TaskID
where timeEntry.DateEntity.Month == currentMonth && timeEntry.DateEntity.Year == DateTime.Today.Year
select new
{
HoursEntered = timeEntry.HoursEntered,
Billable = ta.Billable
})
group x by x.Billable into g
select new
{
IsBillable = g.Key,
Billabe = g.Where(t => t.Billable == true).Sum(x => x.HoursEntered),
NonBillable = g.Where(t => t.Billable == false).Sum(x => x.HoursEntered)
};
foreach (var item in userQuery.ToList())
{
Console.WriteLine(string.Format("{0} - {1}", item.IsBillable? "Billable":"Non-Billable",item.IsBillable?item.Billabe:item.NonBillable));
}

How to write a LINQ statement with a GroupBy condition

I have this LINQ statement as follows;
var RequestList = (from emp in _employeeIds
from x in db.AnnualLeaveBookeds
where x.EmployeeId == emp
orderby x.AnnualLeaveDate
select new RequestInfo
{
AnnualLeaveBookedId = x.AnnualLeaveBookedId,
AnnualLeaveDate = x.AnnualLeaveDate,
MorningOnlyFlag = x.MorningOnlyFlag,
AfternoonOnlyFlag = x.AfternoonOnlyFlag,
Forename = x.Employee.Forename,
Surname = x.Employee.Surname,
EmployeeId = x.Employee.EmployeeId,
RequestDate = x.RequestDate,
CancelRequestDate = x.CancelRequestDate,
ApprovedFlag = (x.ApprovalDate.HasValue && x.ApproverId != Employee.LoggedInUser.EmployeeId),
ApproveFlag = false,
RejectFlag = false,
Reason = string.Empty,
FontColour = "Black"
})
.ToList();
For every RequestInfo I return a FontColour property of Black.
However if I have 2 or more RequestInfo objects with the same AnnualLeaveDate, I want the FontColour to be set to red.
How do I rewrite this query to do that?
Try something like this:
var RequestList = (
from emp in _employeeIds
from x0 in db.AnnualLeaveBookeds
where x0.EmployeeId == emp
orderby x0.AnnualLeaveDate
group x0 by x0.AnnualLeaveDate into xs
from x in xs
select new RequestInfo
{
AnnualLeaveBookedId = x.AnnualLeaveBookedId,
AnnualLeaveDate = x.AnnualLeaveDate,
MorningOnlyFlag = x.MorningOnlyFlag,
AfternoonOnlyFlag = x.AfternoonOnlyFlag,
Forename = x.Employee.Forename,
Surname = x.Employee.Surname,
EmployeeId = x.Employee.EmployeeId,
RequestDate = x.RequestDate,
CancelRequestDate = x.CancelRequestDate,
ApprovedFlag = (x.ApprovalDate.HasValue
&& x.ApproverId != Employee.LoggedInUser.EmployeeId),
ApproveFlag = false,
RejectFlag = false,
Reason = string.Empty,
FontColour = xs.Count() > 1 ? "Red" : "Black"
}).ToList();

LINQ: Group By + Where in clause

I'm trying to implement a T-SQL equivalent of a where in (select ...) code in LINQ.
This is what I have now:
int contactID = GetContactID();
IEnumerable<string> threadList = (from s in pdc.Messages
where s.ContactID == contactID
group 1 by new { s.ThreadID } into d
select new { ThreadID = d.Key.ThreadID}).ToList<string>();
var result = from s in pdc.Messages
where threadList.Contains(s.ThreadID)
group new { s } by new { s.ThreadID } into d
let maxMsgID = d.Where(x => x.s.ContactID != contactID).Max(x => x.s.MessageID)
select new {
LastMessage = d.Where(x => x.s.MessageID == maxMsgID).SingleOrDefault().s
};
However, my code won't compile due to this error for the ToList():
cannot convert from
'System.Linq.IQueryable<AnonymousType#1>'
to
'System.Collections.Generic.IEnumerable<string>'
Anyone have any suggestions on how to implement this? Or any suggestions on how to simplify this code?
Your query returns a set of anonymous types; you cannot implicitly convert it to a List<string>.
Instead, you should select the string itself. You don't need any anonymous types.
Change it to
var threadList = pdc.Messages.Where(s => s.ContactID == contactID)
.Select(s => s.ThreadID)
.Distinct()
.ToList();
var result = from s in pdc.Messages
where threadList.Contains(s.ThreadID)
group s by s.ThreadID into d
let maxMsgID = d.Where(x => x.ContactID != contactID).Max(x => x.MessageID)
select new {
LastMessage = d.Where(x => x.MessageID == maxMsgID).SingleOrDefault()
};

Resources