Composite group join - linq

I want to do a group join with the following three tables using linq extension methods
Custumer
Order
OrderShippingInfo
Custumer can have many Orders and each order can have only one OrderShippingInfo.
So my goal is do a group join of these 3 tables and return a anonymous object that has one Customer and an array of {Order, OrderShippinfo}.
I know how to do a groupjoin between customer and order but I don't know how to add the OrderShippInfo in the collection
Customer.GroupJoin(Order, c=>c.customerID, o=>o.CustomerID, (c,o)=> new {c,o})
Thanks a lot

How about that:
Customer.GroupJoin(Order.Join(OrderShippinInfo,
o=>o.OrderID,
s=>s.OrderID,
(o, s) => new { Order = o, ShippingInfo = s}),
c=>c.customerID,
oi=>oi.Order.CustomerID,
(c,oi)=> new {c,oi})

Related

LINQ: order results of join based on inner collection

Is it possible to order the results of a LINQ join operation based on the inner collection order?
Say I have two collections:
var names = new[]{"John", "Mary", "David"};
var persons= new[]{ new Person{Name="John", Title"Prof"}, new Person{Name="Mary", Title="Accountant"}, new Person{Name="David", Title="Mechanic"}, new Person{Name="Peter", Title="Homeless"}}
if I do a LINQ join to get a subset of persons as follows:
var taxPayers =
persons
.Join(names , p => p.Name, n => n, (p, n) => p)
.Select(f => new KeyValuePair<string, object>(f.Name, f.Title));
The result is ordered based on the persons array.
It is possible using LINQ, to order taxPayers based on the order of names? Or is this not a LINQable operation?
TIA.
Simply reversing the join should work. Instead of joining names to persons, join persons to names.

Need help Understanding Linq group by with joins

Hi I created this Linq query
var k = from account in _session.All<AccountDetail>()
join subscriber in _session.All<Subscriber>() on account.ID equals subscriber.AccID
join subscriberServices in _session.All<SubscriberServce>() on subscriber.ID equals subscriberServices.UserID
join paymentMethod in _session.All<PaymentMethod>() on subscriberServices.PaymentMethod_ID equals paymentMethod.ID
join paymentFrequency in _session.All<PaymentFrequency>() on subscriberServices.PaymentFrequency_ID equals paymentFrequency.ID
group account by new {AccID= account.ID,paymentFrequency= paymentFrequency.Description,paymentMethod= paymentMethod.Description} into G
select new GenerateInvoiceData() { AccID = G.Key.AccID};
I don't understand
group account by new {AccID= account.ID,paymentFrequency= paymentFrequency.Description,paymentMethod= paymentMethod.Description} into G
why do I specify account when I'm not restricted to it in the anonymous type i.e. I can type paymentFrequency.Description.
The group account part is saying what you want the elements in each group to be. The by new { ... } is what you want the key for each group to be. That's not restricted to being part of the information in an element.
As a simplest example, you might have:
from person in people
group person.FirstName by person.LastName
which would give you groups where the key of each group was the last name of all the people represented in the group, and each element of each group would be the first name of someone.
You might want to read two of my Edulinq blog posts:
How query expressions work
The GroupBy method

Combining LINQ queries to get unique records

I'm trying to figure out a way of combining these 2 LINQ queries. The first one creates a list of holiday customers and the second one de-dupes the list based on the email address.
Whats the most succinct way of combining them?
var allNonBuyers = (from a in allCustomers
where !(from q in db.Quotes
where q.CreationDate > DateTime.Now.AddMinutes(duration)
join p in db.Passengers on q.QuoteGUID equals p.QuoteGUID
where q.PolicyNumber != null
select p.EmailAddress).Contains(a.EmailAddress)
select new { a.QuoteGUID, a.Title, a.FirstName, a.LastName, a.EmailAddress, a.Telephone });
var distinctNonBuyers = from buyer in allNonBuyers
group buyer by buyer.EmailAddress
into gbuyer
select gbuyer.First();
You normally don't need to - because LINQ has delayed execution, when you ask for the result it will all be combined. If this is Linq-To-Sql then it will be executed as one statement (if possible) against the database.

ef and linq extension method

I have this sql that i want to have written in linq extension method returning an entity from my edm:
SELECT p.[Id],p.[Firstname],p.[Lastname],prt.[AddressId],prt.[Street],prt.[City]
FROM [Person] p
CROSS APPLY (
SELECT TOP(1) pa.[AddressId],a.[ValidFrom],a.[Street],a.[City]
FROM [Person_Addresses] pa
LEFT OUTER JOIN [Addresses] AS a
ON a.[Id] = pa.[AddressId]
WHERE p.[Id] = pa.[PersonId]
ORDER BY a.[ValidFrom] DESC ) prt
Also could this be re-written in linq extension method using 3 joins?
Assuming you have set the Person_Addresses table up as a pure relation table (i.e., with no data besides the foreign keys) this should do the trick:
var persons = model.People
.Select(p => new { p = p, a = p.Addresses.OrderByDescending(a=>a.ValidFrom).First() })
.Select(p => new { p.p.Id, p.p.Firstname, p.p.LastName, AddressId = p.a.Id, p.a.Street, p.a.City });
The first Select() orders the addresses and picks the latest one, and the second one returns an anonymous type with the properties specified in your query.
If you have more data in your relation table you're gonna have to use joins but this way you're free from them. In my opinion, this is more easy to read.
NOTE: You might get an exception if any entry in Persons have no addresses connected to them, although I haven't tried it out.

multiple grouping, inner joning in Linq

I am trying to translate this into Linq and cannot figure it out:
SELECT
CustomerOrder.ShipState, MONTH(OrderFulfillment.OrderDate) AS Mnth,
YEAR(OrderFulfillment.OrderDate) AS Yer,
SUM(OrderFulfillment.Tax) AS TotalTax
FROM
OrderFulfillment INNER JOIN
CustomerOrder ONOrderFulfillment.OrderID =CustomerOrder.OrderID
WHERE
(OrderFulfillment.Tax > 0)
GROUP BY
CustomerOrder.ShipState, MONTH(OrderFulfillment.OrderDate),
YEAR(OrderFulfillment.OrderDate)
ORDER BY
YEAR(OrderFulfillment.OrderDate) DESC, CustomerOrder.ShipState,
MONTH(OrderFulfillment.OrderDate) DESC
I have Linqpad and have gone through a bunch of the examples but cannot figure this out.
I think you want to do something like this:
from c in CustomerOrder
join o in OrderFulfillment on c.OrderId equals o.OrderId
where
o.Tax > 0
group o by
new { c.ShipState, Mnth = of.OrderDate.Month, Yer = of.OrderDate.Year }
into g
orderby
g.Key.Yer descending, g.ShipState, g.Key.Mnth descending
select
new { g.Key.ShipState, g.Key.Mnth, g.Key.Yer,
TotalTax = g.Sum(i => i.Tax) };
I haven't tried to compile it, but I think this is something along the lines of what you want.
The idea is that first you perform your join to link the customers and orders. Then apply your filter condition.
At that point, you want to get all the orders that have a particular group, so the group operator is applied.
Finally, order the results, then select out all info from the keys for each group, and sum up the tax in each of the group.
First of all, it would be nice to know what exactly you can't figure out. If you're completely lost and don't know where to begin then you need to google around for linq joining and grouping.
Here's something I did recently that may (possibly) point you in the right direction:
// This groups items by category and lists all category ids and names
from ct in Categories
join cst in Category_Subtypes
on ct.Category_Id equals cst.Category_Id
join st in Subtypes
on cst.Subtype_Id equals st.Subtype_Id
where
st.Type_Id == new Guid(id)
group ct by new { ct.Category_Id, ct.Display_Text } into ctg
select new
{
Id = ctg.Key.Category_Id,
Name = ctg.Key.Display_Text
}

Resources