Add a Join to this LINQ Query? - c#

So after what felt like a lot of head banging, I have this query:
var widgets = db.Updates
.Where(c => c.Sold.Equals(false))
.GroupBy(c => c.widgetType)
.Select(x => x.OrderByDescending(y => y.TimeStamp).First()).ToList();
widgetGrid.DataSource = widgets;
widgetGrid.DataBind();
Now that I have all the sold widgets I need to add a join, let's say for instance that I want to join the the "Owner" table on ID in Owner equals ID in Widgets and then select Owner.Name and Widget.Style
For the life of me, I seem to be getting nowhere fast... anyone?
As always... I'm deeply grateful for anyone's time in helping me clear out my cobwebs.

If I understand you correctly, you have two sequences:
a sequence of Widgets, where each widget has a property Id.
You have a sequence of Owners, where each owner has a property Id
And you want the combination of sequences and owners that have a matching Id.
By the way, probably your widget will have an ownerId or your owner will have a widgetId, but that won't influence the solution.
The join will be as follows:
var joinedTable = widgets.join(owners, // join table widgets with table owners
w => w.Id // from widgets take the Id
o => o.Id // from owners also take the Id
(widget, owner) => new // where those Ids match, take the owner and the widget
{ // and take the properties you want
Id = widget.Id,
MyXProperty = owner.X,
MyYProperty = widget.Y,
Widget = widget, // or take the complete widget and owner
Owner = owner,
});
By the way, you write "Now that I have all the sold widgets". From your piece of code I understand that each Update has a Boolean property Sold and that you want all Updates where !Sold. I'd assume you end up with items that are not sold?
What is the advantage of your predicate in the where clause. Why isn't it:
var widgets = db.Updates.Where(c => !c.Sold)
.GroupBy // etc.

You could do this:
var widgets = db.Updates
.Where(c => !c.Sold)
.GroupBy(c => c.widgetType)
.Select(x => x.OrderByDescending(y => y.TimeStamp).FirstOrDefault());
var result= (from w in widgets
join o in db.Owners on w.OwnerId equals o.Id
select new {o.Name, w.Style}).ToList();

you may also try:
var widgets = db.Updates
.Where(c => c.Sold.Equals(false))
.GroupBy(c => c.widgetType)
.Select(x => x.OrderByDescending(y => y.TimeStamp).First())
.Join( db.Owners,
u => u.ID,
o => o.ID,
(u, o) => new { o.Name, u.Style }).ToList();

Related

Linq or EF - Multiple join into non anonymous object with filtered attributes

I am using EF and unfortunately includefiltered is not option. So I have to rewrite my code somehow and create non anonymous object from it. I decided to rewrite it to join but it can be anything that works.
I have entity, simplified version Car.Tires.Manufacturers.
Car can have zero to many tires, tires can have zero to many manufacturers
I want to get car with specific id and only it's tires with specific manufacturer.
The problem is that my result car's tires always have null manufacturers.
My current code is :
var car1 = (from c in this.dbContext.Cars
.Include(cr => cr.Tires)
.ThenInclude(crt => crt.Manufacturers)
join t in this.dbContext.Tires
.Include(ct => ct.Manufacturers)
on c.ID equals t.CarID into carTires
from t in carTires.DefaultIfEmpty()
join m in this.dbContext.Manufacturers on t.ManufacturerID equals m.ID into completeSet
from cs in completeSet.DefaultIfEmpty()
where (c.ID == someCarID ) // and later I will add filter for tire's manufacturer
select new Car
{
ID = c.ID,
Tires = c.Tires
}
If I use code
var car2 = this.dbContext.Cars
.Include(c => c.Tires)
.ThenInclude(t => t.Manufacturers)
Where(c => c.ID == someCarID)
In Car2 there are some manufacturers.
Why car1 Tire's manufacturers is null and how to fix it?
Note: This is middle goal. My final goal is to obtain car with tires only for selected manufacturer.
Try:
var manufacturerTires = dbContext.Tires.Where(t => t.ManufacturerID == someManufacturerID);
var carTires = dbContext.Cars.
Where(car => car.ID == someCarID)
.Join(manufacturerTires,
car => car.ID,
tire => tire.CarID,
(car, tire) => new { car, tire })
.ToList();
This should return an anonymous object new { Car, Tire }
if we need to get the existing structure of Car and Car.Tires, we could add a GroupBy at the end of the above query like:
.GroupBy(c => c.car, c => c.tire, (car, tires) => new Car{ ID = car.ID, Tires = tires});
//this could be an expensive query as the GroupBy is on all the columns in Car table
Try this :
var Cars=this.dbContext.Cars.Where(c => c.ID == someCarID).Select(s=> s.Tires).ToList();
Now you have tires with there Manufacturers

LINQ: join between results of two separate contexts

I know LINQ doesn't support two diff contexts in a standard 'join'.
Having said that, what I'm trying to do is, pull together a list of, shall we say, 'employees', from a 'user' and 'contact' contexts.
(These are edmx's that are from an old project, that I'm not about to mess with.)
Thing is, 'users' is WHO I want to get, but their demographics reside inside the 'contacts'. Here's the two current LINQ's:
var users = _pets_dc.Users
.Select(p => p)
.Where(x => x.Active)
.ToList();
var contacts = _poems_dc.Contacts
.Select(p => p)
.Where(x => x.Active)
.ToList();
I need contacts where 'user.Contact_GUID' equals 'contacts.Contact_GUID'.
I have tried:
var query = contacts
.Where(x => x.Contact_GUID == users
.Select(y => y.Contact_GUID)
.FirstOrDefault());
to no avail... this only brings back one contact, but won't work without .FirstOrDefault(). Any ideas?
If you are using Contact_GUID in both tables if you have FK in users table try using first query with include
var users = _pets_dc.Users.Include("Contacts")
.Where(x => x.Active)
.ToList();
you can try the following anyway:
var joined = from list1 in users
join list2 in contacts
on list1.Contact_GUID equals list2.Contact_GUID
select new { list1, list2 };
ref : https://stackoverflow.com/a/2724018/1166597
You can use below code:
var result = users.Select(e => contacts.Where(x => x.Contact_GUID == e.Contact_GUID));
Joining is one of the option that would work here, but you can modify your current solution as follows:
var query = contacts
.Where(x => users
.Select(y => y.Contact_GUID).Contains(x.Contact_GUID)
).FirstOrDefault());
Contains will check the Guid in a given list, in original solution you are comparing Guid with List<Guid>, which would fail
Option 1:
var query = from person in users
join contact in contacts on person.Contact_GUID equals contact.GUID into employees
from employee in employees.DefaultIfEmpty()
select new Employee() { User = person, Demographic = employee.Demographic };
var employees = query.ToList();
Option 2:
var query = from person in users
join contact in contacts on person.Contact_GUID equals contact.GUID into employees
from employee in employees.DefaultIfEmpty()
select new { person.FirstName, person.LastName, employee.Demographic };
var employees = query.ToList();

Linq to DataSet

I want to pick up all Sellers that aren't boss of a department.
How can I make this? In this query below, only the Sellers that are bosses of a department are picked up, I want the opposite of thereof.
My query:
var query = db.Sellers
.Join(db.Departments,
s => s.Id,
d => d.BossId,
(s, d) => new { Seller = s, Department = d })
.Where(a => a.Seller.Id == a.Department.BossId) ????
.Select(x => x.Seller).ToList();
In the "Where" part, I tried a => a.Seller.Id != a.Department.BossId, but it's wrong I have 3 sellers that aren't bosses.
I tried with this way too:
var listNonBoss = (from s in db.Sellers
join d in db.Departments on s.Id equals d.BossId
select s.Id).ToList();
I want just the opposite of these queries.
Sometimes it's easier to break it into multiple steps.
First, get the collection of all boss IDs:
var bossIDs = db.Departments.Select(x => x.BossId);
Then get all sellers whose IDs are not in that collection:
var listNonBoss = db.Sellers.Where(x => !bossIDs.Contains(x.Id)).ToList();
Join in your code will do an inner join, meaning it'll filter out sellers who don't have a boss.
To do the opposite you can do an outer join, and then remove the ones who have a boss. In fluent LINQ an outer join is done by doing a GroupJoin and then SelectMany.
Something like this:
var query = db.Sellers
.GroupJoin(db.Departments, s => s.Id, d => d.BossId, (s, d) => new { Seller = s, Department = d })
.SelectMany(x => x.d.DefaultIfEmpty(), (seller, department) => new { s.seller, department})
.Where(a => a.department.BossId == null)
.Select(x => x.Seller).ToList();
Or, using query syntax:
var listNonBoss = (from s in db.Sellers
join d in db.Departments on s.Id equals d.BossId into joinedTable
from jt in joinedTable.DefaultIfEmpty()
where jt.BossId == null
select s.Id).ToList();

LINQ Group By and select collection

I have this structure
Customer
- has many Orders
- has many OrderItems
I want to generate a list of CustomerItems via LINQ given a subset of OrderItems:
List of new { Customer, List<OrderItem> Items }
which is a grouping of all the items a Customer has ordered from the subset of items
How can i use LINQ to back track through the order and group by Customer to generate this object?
so far I'm on something like
items
.GroupBy(i => i, i => i.Order.Customer, (i, customer) => new {customer, i})
But thats obviously not a List. I'm guessing I need a SelectMany in there somewhere, but could do with some pointers.
I think you want:
items.GroupBy(item => item.Order.Customer)
.Select(group => new { Customer = group.Key, Items = group.ToList() })
.ToList()
If you want to continue use the overload of GroupBy you are currently using, you can do:
items.GroupBy(item => item.Order.Customer,
(key, group) => new { Customer = key, Items = group.ToList() })
.ToList()
...but I personally find that less clear.
you may also like this
var Grp = Model.GroupBy(item => item.Order.Customer)
.Select(group => new
{
Customer = Model.First().Customer,
CustomerId= group.Key,
Orders= group.ToList()
})
.ToList();
you can achive it with group join
var result = (from c in Customers
join oi in OrderItems on c.Id equals oi.Order.Customer.Id into g
Select new { customer = c, orderItems = g});
c is Customer and g is the customers order items.

How to join 3 tables with lambda expression?

I have a simple LINQ lambda join query but I want to add a 3rd join with a where clause. How do I go about doing that?
Here's my single join query:
var myList = Companies
.Join(
Sectors,
comp => comp.Sector_code,
sect => sect.Sector_code,
(comp, sect) => new {Company = comp, Sector = sect} )
.Select( c => new {
c.Company.Equity_cusip,
c.Company.Company_name,
c.Company.Primary_exchange,
c.Company.Sector_code,
c.Sector.Description
});
I want to add the following SQL command to the above LINQ query and still maintain the projections:
SELECT
sector_code, industry_code
FROM
distribution_sector_industry
WHERE
service = 'numerical'
The 3rd join would be made with Sector table & Distribution_sector_industry on sector_code.
Thanks in advance.
Just a guess:
var myList = Companies
.Join(
Sectors,
comp => comp.Sector_code,
sect => sect.Sector_code,
(comp, sect) => new { Company = comp, Sector = sect })
.Join(
DistributionSectorIndustry.Where(dsi => dsi.Service == "numerical"),
cs => cs.Sector.Sector_code,
dsi => dsi.Sector_code,
(cs, dsi) => new { cs.Company, cs.Sector, IndustryCode = dsi.Industry_code })
.Select(c => new {
c.Company.Equity_cusip,
c.Company.Company_name,
c.Company.Primary_exchange,
c.Company.Sector_code,
c.Sector.Description,
c.IndustryCode
});
Okay, I can't see why you'd want to select sector_code when you already know it, but I think you want this:
var query = from company in Companies
join sector in Sectors
on company.SectorCode equals sector.SectorCode
join industry in DistributionSectorIndustry
on sector.SectorCode equals industry.SectorCode
where industry.Service == "numerical"
select new {
company.EquityCusip,
company.CompanyName,
company.PrimaryExchange,
company.SectorCode,
sector.Description,
industry.IndustryCode
};
Notes:
I've changed it into a query expression as that's a much more readable way of expressing a query like this.
Although the "where" clause comes after the join, assuming this is a LINQ to SQL or Entity Framework query, it shouldn't make any difference
I've lengthened the range variable names for clarity
I've converted your other names into conventional .NET names; you can do this too in your model
For 4 Tables
var query = CurrencyDeposits
.Join(Customers, cd => cd.CustomerId, cus => cus.Id, (cd, cus)
=> new { CurrencyDeposit = cd, Customer = cus })
.Join(Currencies, x => x.CurrencyDeposit.CurrencyId, cr => cr.Id, (x, cr)
=> new { x.CurrencyDeposit, x.Customer, Currency = cr })
.Join(Banks, x => x.CurrencyDeposit.BankId, bn => bn.Id, (x, bn)
=> new { x.CurrencyDeposit, x.Customer, x.Currency, Bank = bn})
.Select(s => new {
s.CurrencyDeposit.Id,
s.Customer.NameSurname,
s.Currency.Code,
s.Bank.BankName,
s.CurrencyDeposit.RequesCode
});
Try something like this...
var myList = ({from a in Companies
join b in Sectors on a.Sector_code equals b.Sector_code
join c in Distribution on b.distribution_code equals a.distribution_code
select new {...});

Categories

Resources