LINQ select problems - linq

from item in db.Items
join ci in db.ChainStoreItems on item.ItemId equals ci.ItemId
where ci.ChainStoreId == 2
select item
The problem is as follows: Item has a set of ChainStoreItems. I want to write a query which returns an Item which doesn't have a set of ChainStoreItems it should hold only the one specific ChainStoreItem for the selected ChainStore.
So I only want do have the additional columns in item which came from ChainStoreItem however this is possible
That's a SQL statement which would do what I want
SELECT
ChainStoreItems.ChainStoreId, ChainStoreItems.ItemId,
Item.ProcStatus, Item.Del, Item.LastUpdate,
ChainStoreItems.AllowToReturn,
ChainStoreItems.AllowToSale
FROM
ChainStoreItems
INNER JOIN
Item ON ChainStoreItems.ItemId = Item.ItemId
WHERE
(ChainStoreItems.ChainStoreId = 140)

Is this what you are getting at!?
var result = from item in db.Items
join ci in db.ChainStoreItems
on item.ItemId equals ci.ItemId
where ci.ChainStoreId == 2
into itemci // note grouping
select new
{
//Whatever you want in here
};
return result;
Sorry i'm still not quite seeing what exactly it is you want to achieve. As far as i'm aware it's simply a matter of creating a join and pulling back the appropriate details

Does ChainStoreItem have an Item property?
In which case, is it just:
from csi in ChainStoreItems
where csi.ChainStoreId == 140
select new { ChainStoreItem = csi, Item = csi.Item }
... or have I misunderstood?

Related

LINQ Left join on my than one field? I have the SQL working but can't convert it to a linq query

I wonder if anyone can help
I have a simple SQL Query which was this.
SELECT * FROM ITEM INNER JOIN CODES ON ITEM.ITEMID = CODES.ITEMID AND
ITEM.CATID = CODES.CATID
This works great, so i created the following query in LINQ
from i in Item join c in codes
on new { i.itemid, i.catid } equals new { c.itemid, c.catid }
Works great, but they i realized that i actually needed an LEFT JOIN in place of the INNER JOIN. So the sql, which now works great!, is :- (notice left join)
SELECT * FROM ITEM LEFT JOIN CODES ON ITEM.ITEMID = CODES.ITEMID AND
ITEM.CATID = CODES.CATID
So now everything seems to work and i get back the data i require using SQL i can't figure out how to do a left join in LINQ and especially how to do a left join on more than 1 field - in my case itemid and catid
I wonder if anyone can lend a hand, i am stuck :-)
I think this is the direction you need to head down:
from i in Item
join c in codes on new { i.itemid, i.catid } equals new { c.itemid, c.catid }
into grouped
from g in grouped.DefaultIfEmpty()
select new
{
ItemId = c.itemid,
CatItemId = g != null ? g.itemid : "Empty"
};
You should look: http://codingsense.wordpress.com/2009/03/08/left-join-right-join-using-linq/
The key is -->
into JoinedEmpDept
from dept in JoinedEmpDept.DefaultIfEmpty()

LINQ SubCollection SubSelect

Hello – I’m trying to get a where condition to apply to a sub collection. I can get the criteria to return the proper parents. However, I want the sub collection to be limited to the criteria as well.
In my example code, I only want people with “LINK” skills; also, I only want the skills for each person to equal “LINK.” That is, each person should only have “LINK” for their skills.
Thanks in advance.
List<Skill> skills = new List<Skill>();
skills.Add(new Skill(){SkillName="ASP.NET"});
skills.Add(new Skill(){SkillName="C#"});
Person p1 = new Person(){ Name="Me", Skills=skills} ;
List<Skill> skills2 = new List<Skill>();
skills2.Add(new Skill(){SkillName="ASP.NET"});
skills2.Add(new Skill(){SkillName="C#"});
skills2.Add(new Skill(){SkillName="LINQ"});
Person p2 = new Person(){ Name="You", Skills=skills2} ;
List<Person> People = new List<Person>();
People.Add(p1);
People.Add(p2);
var oResult = (from item in People
from sk in item.Skills
where sk.SkillName == "LINQ"
select item
).ToList();
When I run this. I get p2 (correct), but I want the skills of P2 to only equal LINQ
Do this:
var oResult = (from item in People
where item.Skills.Count() == 1 &&
item.Skills.Any(s => s.SkillName == "LINQ")
select item
).ToList();
This query will return nothing because p2 (You) has other skills in addition to LINQ.
You can do what you want this way:
foreach (var person in oResult)
{
person.Skills.RemoveAll(s => !s.SkillName.Equals("LINQ"));
}
Note: while using LINQ you're only filtering your data. To post process it you use something like the foreach I show you above.
Try this:
var oResult = (from item in People
where item.Skills != null
where item.Skills.Count() > 0
where item.Skills.All(s => s.SkillName == "LINQ")
select item
).ToList();
Even though your example shows that the Skills collection has a value, you want to make sure that your code doesn't blow up if the Skills property is null.
Also, the All predicate returns true if your list is empty so you need to ensure that it is not empty. The above query reads better, but depending on the implementation of the Skills property calling Count() may cause the entire collection to be iterated. You could use Any() instead to ensure that the collection is not empty.
var oResult = (from item in People
where item.Skills != null
where item.Skills.Any()
where item.Skills.All(s => s.SkillName == "LINQ")
select item
).ToList();

LINQ to SQL, sorting by a related table

I'm trying to order the values in a related table using LINQ to SQL.
I have 2 tables. Menu and MenuSection. They are related one to many on Menu.MenuId == MenuSection.MenuId
Currently, I'm pulling this information using the following query
var menus = from m in _context.Menus
select m;
This gets fed into an ASP.NET MVC page and works fine.
I'd like to be able to sort the data the column MenuSection.Order
I've tried doing this:
var menus = from m in _context.Menus
join ms in _context.MenuSections on m.MenuId equals ms.MenuId
orderby ms.Order ascending select m;
But it's bringing back a set of data that is incorrect. It displays repeated Menu information.
EDIT: To clarify what i'm expecting the data shoud be:
There are x Menu's in Menu.
Each Menu has many MenuSection's
I'd like to list out each Menu and their related MenuSection.
The MenuSections need to be in order based on MenuSection.Order
Menu 1
- MenuSection 1, Order = 1
- MenuSection 3, Order = 2
Menu 2
- MenuSection 4, Order = 1
- MenuSection 2, Order = 2
Round 3: That last revision to the question clarifies it a lot. It sounds like what you really need is a group-by. Those are harder to get right without the IntelliSense but I'll try my best:
var groupings =
from m in _context.Menus
orderby m.Foo
from ms in m.MenuSections
orderby ms.Order
group ms by m;
foreach (var group in groupings)
{
Menu menu = group.Key;
// use the Menu
foreach (MenuSection ms in group)
{
// use the MenuSection
}
}
Now I added an extra orderby m.Foo where Foo is some property that I think you might want on Menu. Otherwise you aren't guaranteed to know the order of the top level menus.
Also note what I was saying earlier that the m.MenuSections is really a helper that is similar to from ms in _context.MenuSections where ms.MenuId == m.MenuId.
have you tried something like this? ...
var menus = (from m in _context.Menus
join ms in _context.MenuSections on m.MenuId equals ms.MenuId
orderby ms.Order ascending select m).Distinct();
or maybe this...
var menus = (from m in _context.Menus
join ms in _context.MenuSections on m.MenuId equals ms.MenuId
select new {m, ms.Order})
.OrderBy(x => x.Order)
.Select(x => x.m)
.Distinct();
In that second case, you're projecting the sort column into a new type, sorting on it, then selecting just the original object, and distincting on that.
Just an FYI, I did manage to make this work by sorting as I performed the output.
My original intention was to have a presorted data set to work with.
Here is an example of what I meant:
var menus = from m in _context.Menus select m;
foreach (var menu in menus)
{
Console.WriteLine(menu.Name);
foreach (var menuSection in menu.MenuSections.OrderBy(o => o.Order))
{
Console.WriteLine("\t" + menuSection.Name + ", " + menuSection.Order);
}
}

Help with linq join

I have the following expression in linq (its a join) and i am selecting into "J" because i need to use J later (currently i just selecting J but once i have this fixed i plan on use J within another subquery after)
But it won't let me supply a where using the "V" side hence v.IdOFfice is invalid.
I have tried swapping around the joins and that what happens i can't use the "GVT"..
WIth specifying the where it works perfect but i need to specify 2 wheres that are present in the 2 tables ... hence IdOffice and IdTariff are in there own tables .. they are not both ....
(from gvt in Tariffs
join v in Items
on gvt.IdGroupItem equals v.IdGroupItem
into j
where v.IdOffice == 1 && gvt.IdTariff == 111
select j).Take(50)
Probably something silly, it appears the table specified after the join i am not able to use in the where?
Any ideas?
Thanks
This is basically what i am trying to achieve
from gvt in Tariffs
join v in Items
on gvt.IdGroupItem equals v.IdGroupItem
into j
where v.IdOffice == 1 && gvt.IdTariff == 111
select new
{
id = v.IdItem
Tariff = from j
{
test = j.TariffDesc,
test1 = j.TariffPrice
}
basicaly i end up with 1 record with Id and a field which as many tariffs inside - if this makes sense?
}
Query working great,
it would be nice to be able to use an extension method (c#) like so ... is this possible so i can dynamically set tariff ... so for example i do the query and i have an extension method (which i already use on simple queries) like so
public static IQueryable<Models.ItemTariffCol> WithTariffId(this IQueryable<Models.ItemTariffCol> qry, int tariffId)
{
return from t in qry
where t.IdTarifa == tariffId
select t;
}
this makes it very extensible ? If its a normal where i can do this but the query isn't in the where
Thank you.
You're doing a group join here, since you're using into. This means that for every gvt, you have not one Item, but possibly several (or none). The list of all items is stored in j, as an IEnumerable<Item>. If you want to select all tariffs for which there's at least one item with IdOffice == 1, then you can do it like this:
from gvt in Tariffs
join v in Items
on gvt.IdGroupItem equals v.IdGroupItem
into j
where gvt.IdTariff == 111 && j.Any(v => v.IdOffice == 1)
...
After the answer edit, it seems that you've started from the wrong direction as well - so far as I can see, you want a list of tariffs for every item, not the list of items for every tariff. For that, you need to reverse your join:
from item in Items
join tariff in Tariffs
on item.IdGroupItem equals tariff.IdGroupItem
into tariffs
where item.IdOffice == 1
select new
{
Id = item.IdItem,
Tariffs = from tariff in tariffs
where tariff.IdTariff == 111
select new { tariff.TariffDesc, tariff.TariffPrice }
}
Or you could filter tariffs right in the join:
from item in Items
join tariff in (from t in Tariffs where t.IdTariff == 111 select t)
on item.IdGroupItem equals tariff.IdGroupItem
into tariffs
where item.IdOffice == 1
select new
{
Id = item.IdItem,
Tariffs = from tariff in tariffs
select new { tariff.TariffDesc, tariff.TariffPrice }
}

Stuck on a subquery that is grouping, in Linq`

I have some Linq code and it's working fine. It's a query that has a subquery in the Where clause. This subquery is doing a groupby. Works great.
The problem is that I don't know how to grab one of the results from the subquery out of the subquery into the parent.
Frst, here's the code. After that, I'll expplain what piece of data i'm wanting to extract.
var results = (from a in db.tblProducts
where (from r in db.tblReviews
where r.IdUserModified == 1
group r by
new
{
r.tblAddress.IdProductCode_Alpha,
r.tblAddress.IdProductCode_Beta,
r.tblAddress.IdProductCode_Gamma
}
into productGroup
orderby productGroup.Count() descending
select
new
{
productGroup.Key.IdProductCode_Alpha,
productGroup.Key.IdProductCode_Beta,
productGroup.Key.IdProductCode_Gamma,
ReviewCount = productGroup.Count()
}).Take(3)
.Any(
r =>
r.IdProductCode_Alpha== a.IdProductCode_Alpha&&
r.IdProductCode_Beta== a.IdProductCode_Beta&&
r.IdProductCode_Gamma== a.IdProductCode_Gamma)
where a.ProductFirstName == ""
select new {a.IdProduct, a.FullName}).ToList();
Ok. I've changed some field and tables names to protect the innocent. :)
See this last line :-
select new {a.IdProduct, a.FullName}).ToList();
I wish to include in that the ReviewCount (from the subquery). I'm jus not sure how.
To help understand the problem, this is what the data looks like.
Sub Query
IdProductCode_Alpha = 1, IdProductCode_Beta = 2, IdProductCode_Gamma = 3, ReviewCount = 10
... row 2 ...
... row 3 ...
Parent Query
IdProduct = 69, FullName = 'Jon Skeet's Wonder Balm'
So the subquery grabs the actual data i need. The parent query determines the correct product, based on the subquery filters.
EDIT 1: Schema
tblProducts
IdProductCode
FullName
ProductFirstName
tblReviews (each product has zero to many reviews)
IdProduct
IdProductCode_Alpha (can be null)
IdProductCode_Beta (can be null)
IdProductCode_Gamma (can be null)
IdPerson
So i'm trying to find the top 3 products a person has done reviews on.
The linq works perfectly... except i just don't know how to include the COUNT in the parent query (ie. pull that result from the subquery).
Cheers :)
Got it myself. Take note of the double from at the start of the query, then the Any() being replaced by a Where() clause.
var results = (from a in db.tblProducts
from g in (
from r in db.tblReviews
where r.IdUserModified == 1
group r by
new
{
r.tblAddress.IdProductCode_Alpha,
r.tblAddress.IdProductCode_Beta,
r.tblAddress.IdProductCode_Gamma
}
into productGroup
orderby productGroup.Count() descending
select
new
{
productGroup.Key.IdProductCode_Alpha,
productGroup.Key.IdProductCode_Beta,
productGroup.Key.IdProductCode_Gamma,
ReviewCount = productGroup.Count()
})
.Take(3)
Where(g.IdProductCode_Alpha== a.IdProductCode_Alpha&&
g.IdProductCode_Beta== a.IdProductCode_Beta&&
g.IdProductCode_Gamma== a.IdProductCode_Gamma)
where a.ProductFirstName == ""
select new {a.IdProduct, a.FullName, g.ReviewCount}).ToList();
While I don't understand LINQ completely, but wouldn't the JOIN work?
I know my answer doesn't help but it looks like you need a JOIN with the inner table(?).
I agree with shahkalpesh, both about the schema and the join.
You should be able to refactor...
r => r.IdProductCode_Alpha == a.IdProductCode_Alpha &&
r.IdProductCode_Beta == a.IdProductCode_Beta &&
r.IdProductCode_Gamma == a.IdProductCode_Gamma
into an inner join with tblProducts.

Resources