Lambda query previous parameter access - c#

Is possible to access a parameter variable of a previous condition?
How to do this?
var result = collectionA
.First(a => a.id == 1)
.CollectionB
.SelectMany(b => b.CollectionC)
.Select(c => new { propA = a.id, propC = c.id });

You can write
var result = collectionA
.Where(q => q.id == 1).Take(1) //it will be collection of 1 element
.Select(a => a
.CollectionB
.SelectMany(b => b.CollectionC)
.Select(c => new { propA = a.id, propC = c.id })).First();
or
(new [] { collectionA.First(q => q.id == 1) })
.Select(a => a
....
or just
var a = collectionA.First(q => q.id = 1);
a.Select( .....

The solution based on #Artem's answer:
var result = CollectionA
.Where(a => a.id == 1)
.SelectMany(b =>
b.CollectionB
.SelectMany(c => c.CollectionC)
.Select(c => new { b.id, c.id })
);

Related

c# Lambda referencing class object in Select method

I've written this code which works:
var uniqueCustomerIdList = services
.GroupBy(x => x.CustomerId)
.Select(cl => new Customer
{
CustomerId = cl.First().CustomerId,
CustomerName = cl.First().CompanyName,
PdfServices = services.Where(x => x.CustomerId == cl.First().CustomerId).ToList(),
PdfServiceLines = services.Where(x => x.CustomerId == cl.First().CustomerId).ToList()
.GroupBy(l => l.ServiceDescription)
.Select(cy => new PdfServiceLine
{
ServiceName = cy.First().ServiceDescription,
Quantity = cy.Count(),
UnitPrice = cy.First().PlanCharge,
ServiceCharges = services.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill),
UsageCharges = usage.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.Charge),
Total = cy.Sum(c => c.PlanCharge),
}).ToList(),
PdfUsages = usage.Where(x => x.CustomerId == cl.First().CustomerId).ToList()
})
.ToList();
I wanted to know if it's possible to reference values from the outer Select statement in the inner statement? As it looks rather clunky at the moment.
For instance in the outer Customer select I use PdfServices - can I use that in the inner select where I have ServiceCharges?
ServiceCharges = PdfServices.Where(s => s.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill)
instead of
ServiceCharges = services.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill),
Thanks,
Lee.
The results that you want to re-use are members of an anonymous object, not variables. As such, you cannot expect them to be available, like a variable would be, to the inner lambda. If you re-wrote your statement, you could store them in intermediate variables:
var uniqueCustomerIdList = services
.GroupBy(x => x.CustomerId)
.Select(cl =>
{
var pdfServices = services.Where(x => x.CustomerId == cl.First().CustomerId).ToList();
return new Customer
{
CustomerId = cl.First().CustomerId,
CustomerName = cl.First().CompanyName,
PdfServices = pdfServices,
PdfServiceLines = pdfServices
.GroupBy(l => l.ServiceDescription)
.Select(cy => new PdfServiceLine
{
ServiceName = cy.First().ServiceDescription,
Quantity = cy.Count(),
UnitPrice = cy.First().PlanCharge,
ServiceCharges = services.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill),
UsageCharges = usage.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.Charge),
Total = cy.Sum(c => c.PlanCharge),
}).ToList(),
PdfUsages = usage.Where(x => x.CustomerId == cl.First().CustomerId).ToList()
};
})
.ToList();
Note that the lamda body now uses curly braces and a return statement. This is not convertible to an expression tree, and some ORM frameworks, like Entity Framework, will not be able to translate the lamda into SQL.

How do i do the "IN" and "DISTINCT of SQL to LINQ

SELECT DISTINCT MarketTemplateId AS MarketTemplateID
FROM Market
WHERE Market.FixtureId = ? And
Market.MarketTemplateId In
('MW3W', '1HTG', 'FTCS', 'HTFT', 'MTG2W', 'MW3W1H','FTCSALT')
how would i produce this in LINQ because i tried the below code and it doesn't work
var result6 = entityTrading.Markets
.Where(p => p.FixtureId == InternalFixtureID_F.ToString())
.FirstOrDefault(p => MarketTemplateIds.Contains(p.MarketTemplateId));
List<string> MarketTemplateIds = new List<string>{ "MW3W", "1HTG", "FTCS", "HTFT", "MTG2W", "MW3W1H","FTCSALT" };
var result6 = entityTrading.Markets
.Where(p => p.FixtureId == InternalFixtureID_F.ToString()
and MarketTemplateIds.Contains(p.MarketTemplateId ))
.Select( u => u.MaketTemplateId).Distinct();
How about
var id = InternalFixtureID_F.ToString();
var result6 = entityTrading.Markets
.Where(p => p.FixtureId == id && MarketTemplateIds.Contains(p.MarketTemplateId))
.Select(m => m.MarketTemplateId)
.Distinct();

Lambda for Groupby and Sum?

var product = db.Products
.Where(x => x.ProductKey == 310)
.Join(db.InternetSales, p => p.ProductKey,
c => c.ProductKey, (p, c) => c)
.SingleOrDefault();
This is my query but I dont know how to group it by ProductName and Sum the Sales Amount.
Try this:
var product = db.Products.Where(x => x.ProductKey == 310)
.Join(db.InternetSales, p => p.ProductKey,
c => c.ProductKey, (p, c) => c)
.GroupBy(c => c.ProductName)
.Select(g => new { g.Key, TotalSales = g.Sum(x => x.Sales) })
.SingleOrDefault();
Or if you only need the sum, try this:
var totalSales = db.Products.Where(x => x.ProductKey == 310)
.Join(db.InternetSales, p => p.ProductKey,
c => c.ProductKey, (p, c) => c)
.GroupBy(c => c.ProductName)
.SingleOrDefault()
.Sum(x => x.Sales);
You don't need Join at all, because you already have ProductKey which is then used to join InternetSales table.
I think you can end up with following:
var TotalSales = db.InternetSales
.Where(s => s.ProductKey == 310)
.Select(s => s.Sales)
.Sum();

OrderByDescending doesn't work in nested linq statement

In Linqpad, i can see the correct list. But in code, after putting in the list collection, order by doesn't work for BeginDate. If i use BeginDate with Max, it works. I don't understand where i am wrong?
var templist = contentRepository
.Get(q => (q.Status == (int)StatusEnum.Active) &&
(q.CategoryId == category.GetHashCode() || q.Category.ParentId == category.GetHashCode())
&& q.MinorVersion == 0
&& q.MajorVersion > 0)
.GroupBy(q => q.VersionId)
.OrderByDescending(q => q.Key)
.Select(q => new
{
VersionId = q.Key,
Id = q.Max(x => x.Id),
MajorVersion = q.Max(x => x.MajorVersion),
UpdatedAt = q.Max(x => x.UpdatedAt),
//BeginDate = q.Max(x=>x.BeginDate),
BeginDate = (q.OrderByDescending(x => x.Id).Take(1).Select(x=>x.BeginDate)).First(),
Title = (q.OrderByDescending(x => x.Id).Take(1).Select(x => x.Title)).First(),
ShowOnHomePage = (q.OrderByDescending(x => x.Id).Take(1).Select(x=>x.ShowOnHomePage)).First()
})
.OrderByDescending(x => x.BeginDate)
.Take(maxItemCount)
.ToList();
List<ContentEntity> contents = new List<ContentEntity>();
templist.ForEach(q => contents.Add(
contentRepository
.Get(x => x.VersionId == q.VersionId && x.MajorVersion == q.MajorVersion && x.MinorVersion == 0)
.FirstOrDefault()
));
return contents.Where(q => q.ShowOnHomePage == true)
.OrderByDescending(q => q.MajorVersion)
.OrderByDescending(q => q.BeginDate)
.Take(maxItemCount)
.ToList();
You are ordering by Id, not by BeginDate. Equivalent code for
q.Max(x => x.BeginDate)
Will be
q.OrderByDescending(x => x.BeginDate).Take(1).Select(x => x.BeginDate).First()
Or simplified
q.OrderByDescending(x => x.BeginDate).First().BeginDate

Linq orderby, can't work out how to use it

I have this function:
/// <summary>
/// Return array of all badges for a users
/// </summary>
public static Badge[] getUserBadges(int UserID)
{
Badge[] ReturnBadges;
using (MainContext db = new MainContext())
{
var q = db.tblBadgeUsers
.Where(c => c.UserID == UserID)
.GroupBy(c => c.BadgeID)
.Select(c => new { BadgeCount = c.Count(), TheBadge = c });
ReturnBadges = new Badge[q.Count()];
int i = 0;
foreach (var UserBadge in q)
{
ReturnBadges[i] = new Badge(UserBadge.TheBadge.Key);
ReturnBadges[i].Quantity = UserBadge.BadgeCount;
i++;
}
}
return ReturnBadges;
}
I wish to order by tblBadges.OrderID ascending but I can't seem to find out where to put it, can anyone help?
I've tried:
.OrderBy(c=> c.TheBadge.OrderID)
But it's not valid code. TheBadge.Key in the loop is a tblBadges type. It's confusing me a bit why intellisense wont let me do the order by anywhere!
TheBadge isn't a single badge, it's a group of badges... so I'd personally rename it if I were you. Now, which OrderId do you want to get? You've got multiple entities in the gruop. For example, you could do this:
var q = db.tblBadgeUsers
.Where(c => c.UserID == UserID)
.GroupBy(c => c.BadgeID)
.Select(c => new { BadgeCount = c.Count(), TheBadge = c })
.OrderBy(x => x.TheBadge.First().OrderId);
That will order by some notional "first" element - although I don't know what the generated SQL will look like.
If you expect the OrderId to be the same for every badge with the same ID, you might use:
var q = db.tblBadgeUsers
.Where(c => c.UserID == UserID)
.GroupBy(c => new { c.BadgeID, c.OrderID })
.OrderBy(group => group.Key.OrderID)
.Select(c => new { BadgeCount = c.Count(), TheBadge = c });
Try this:
var q = db.tblBadgeUsers
.Where(c => c.UserID == UserID)
.GroupBy(c => c.BadgeID)
.Select(c => new { BadgeCount = c.Count(), TheBadge = c.Key }) // *mod
.OrderBy(c=> c.TheBadge.OrderID); // * added
In the following line, TheBadge is a linq collection, not the badge itself. You want c.Key.
.Select(c => new { BadgeCount = c.Count(), TheBadge = c })

Categories

Resources