Please Consider these 2 tables:
CategoryID CategoryName CategoryModel
-----------------------------------------------------------
1 Book 1
2 Shoe 2
3 Glass 1
and
SubCategoryID SubCategoryName CategoryID SubCategoryModel OtherColumn1 OtherColum2
---------------------------------------------------------------------
1 Book1 1 3
2 Book2 1 1
3 Shoe1 2 2
4 Shoe2 2 2
I want such this query:
from a in Category
join b in SubCategory
on a.CategoryID equals b.CategoryID into grpDetail
where a.CategoryModel != b.SubCategoryModel <----------
select new
{
Id = a.CategoryID,
Count1 = grpDetail.Count(o=>o.OtherColumn1 == 1),
...
}
the problem id I can't access to b in above specifies line. How can I write this query?
Thanks
There is a straightforward one to many relation between Categories and SubCategories: every Category has zero or more SubCategories; every SubCategory belongs to exactly one Category, namely the Category that the foreign key SubCategory.CategoryId refers to.
You want to join Category and SubCategory on this foreign key. You don't want all Category-SubCategory combinations that match, you want only those where Category.CategoryModel is not equal to SubCategory.SubCategoryModel.
From the remaining records, you want to select several properties. I don't see property GrpDetail in your classes, so I don't know what you want.
Luckily you mention that your problem is in the Where:
var result = Categories.Join(SubCategories, // join tables Categories and SubCategories
category => category.Id, // from every category take the Id,
subCategory => subCategory.CategoryId, // from every subCategory take foreign key CategoryId
(category, subCategory) => new // when they match make one new object
{
// we need at least Category.CategoryModel and SubCategory.SubCategoryModel
CategoryModel = category.CategoryModel,
SubCategoryModel = subCategory.SubCategoryModel,
// Select other Category properties that you plan to use:
CategoryId = category.Id,
...
// Select other SubCategory properties that you plan to use:
...
})
// we don't want all combinations, only those where
// CategoryModel is not equal to SubCategoryModel
.Where(joinResult => joinResult.CategoryModel != joinResult.SubCategoryModel)
// from the remaining combinations calculate the final result
.Select(joinResult => new
{
Id = joinResult.CategoryId,
Count1 = ... // sorry, don't know what property grpDetail does
...
});
split your query into 2, first do your join with the where clause and then do your group by.
Related
I have a situation where I have a LINQ query. It has two joins (one to many) but it is bringing back all of the columns in the joined tables. I'm not sure how to create the LINQ query to only being back a few fields from the joined tables.
var data = from mc in ctx.MembershipChapters
where mc.PartitionKey == controllerStateManager.PartitionKey && mc.MembershipId == membershipId
join prd in ctx.Products on mc.ProductId
equals prd.Id into prods
from prd in prods.DefaultIfEmpty()
join oli in ctx.OrderLineItems on mc.OrderLineItemId equals oli.OrderLineItemId into olis
from oli in olis.DefaultIfEmpty()
select new
{
MembershipName = mc.Membership.Name,
Products = prods.Select(p => new {
ProductName = p.Name, ProductId = p.Id }),
OrderLineItems = olis.Select(o => new { OrderLineItemName = o.Description, OrderLineItemId = o.OrderLineItemId })
};
controllerStateManager.Data = data.ToList();
This does not work...I get an error: "o" is not in scope.
Basically the output should follow this:
MembershipChapter
---> OrderLineItems
----------> Products
I'm new to LINQ and I have been struggling on this for far too long.
If you have a one-to-many relationship, and you want the "one" items, each one with its zero or more subitems, like Schools with their zero or more Students; Customers with their zero or more Orders, or, as in your case: MembershipChapters with their OrderLineItems, consider to use one of the overloads of Queryable.GroupJoin.
If you start on the "many" side, and you want each item with its one parent item, so you want the Student with the School he attends, or the Order with the one and only Customer who placed the order, use one of the overloads of Queryable.Join.
I almost always use the overload that has a parameter resultSelector, so you can exactly define what should be in the result.
Requirement: given tables MembershipChapters, OrderLineItems and Products. There is a one-to-many relationship between MembershipChapters and OrderLineItems. Every MembershipChapter has zero or more OrderLineItems, every OrderLineItem belongs to exactly one MembershipChapter, namely the MembershipChapter that the foreign key refers to. There is a similar one to many relation between OrderLineItems and Products. Give me all (or some) MembershipChapters, each MembershipChapter with its zero or more OrderlineItems, and each OrderLineItem with its zero or more Products.
var result = dbContext.MemberShipChapters
.Where(membershipChapter => ...) // only if you don't want all MembershipChapters
.GroupJoin(dbContext.OrderLineItems,
membershipChapter => membershipChapter.Id, // from every membershipChapter get the primary key
orderlineItem => orderLineItem.MembershipChapterId, // from every OrderlineItem get the foreign key
// parameter resultSelector: from every MembershipChapter with its zero or more
// OrderLineItems, make one new:
(membershipChapter, orderLineItemsOfThisMembershipChapter) => new
{
// Select only the membershipChapter properties that you plan to use
Id = membershipChapter.Id,
Name = membershipChapter.Name,
...
// The zero or more OrderLineItems of this membershipChapter
OrderLineItems = orderLineItemsOfThisMembershipChapter
.Select(orderLineItem => new
{
// Select only the OrderLineItems that you plan to use:
Id = orderLineItem.Id,
...
// not needed, you already know the value
// MembershipChapterId = orderLineItem.MembershipChapterId,
})
.ToList(),
});
This is fairly straightforward. However, if you want to GroupJoin three tables, then this looks horrible, although it is doable.
Another method that looks simpler:
var result = dbContext.MemberShipChapters
.Where(membershipChapter => ...)
.Select((membershipChapter => new
{
Id = membershipChapter.Id,
Name = membershipChapter.Name,
...
OrderLineItems = dbContext.OrderLineItems
// keep only the OrderLineItems with a foreign key referring to this MembershipChapter
.Where(orderLineItem => orderLineItem.MemberShipChapterId == membershipChapter.Id)
.Select(orderLineItem => new
{
Id = orderLineItem.Id,
...
// do the same with the third table
Products = dbContext.Products
.Where(product => product.OrderLineItemId == orderLineItem.Id)
.Select(product => new
{
Id = product.Id,
Price = product.Price,
...
})
.ToList(),
})
.ToList(),
});
It is a little hard to read, but if the domain is linked correctly then I think you just want to end up with a query like this:
from ol in ctx.OrderLines where
ol.MembershipChapter.PartitionKey == controllerStateManager.PartitionKey
select new {ol.Whatever, ol.Product.Whatever};
I'm developing a web application using Entity Framework.
I need do a select and pass values for an Ilist but it's returns duplicate values.
IQueryable<establishmentInfo> filter = (from x in db.establishments
join t in db.establishment_categories on x.id equals t.establishment
join q in db.categories on t.category equals q.id
where (x.name.ToUpper().Contains(search.ToUpper()))
select new establishmentInfo
{
id = x.id,
name = x.name,
id_category = q.id,
category = q.name,
});
IList<establishmentInfo>establishments = filter.ToList();
Establishment table
id name email
---------------------------
1 AAA a#a.com
2 BBB b#b.com
Establishment_categories
id establishment category
-------------------------------
1 1 1
2 1 2
3 2 1
Categories
id name
---------------------
1 alpha
2 beta
The problem is that return 2 establishments, one with category 1 and other with category 2. I need remove one of these.
Can anyone help?
As #NetMage said,your linq statement should return two values that are not repeated.
We can see that there are two records with establishment set to 1 in your Establishment_categories table. You can check your establishments. The id_category should be 1, the category should be alpha, the other should be id_categoryis 2, and the category should be beta.
You can see below image:
If you only want to get the first data of establishments, you can write the code as follows:
IQueryable<Establishment> filter = (from x in _context.Establishments
join t in _context.Establishment_Categories on x.Id equals t.EstablishmentId
join q in _context.Categories on t.CategoryId equals q.Id
where x.Name.ToUpper().Contains(search.ToUpper())
select new Establishment
{
Id = x.Id,
Name = x.Name,
CategoryId = q.Id,
CategoryName = q.Name,
}).Take(1);
List<Establishment> establishments = filter.ToList();
Result:
By the way, assuming that there are duplicates in your returned data, you can add the .Distinct() method after your linq to remove duplicates.
I have a Personnel table and PersonnelDrivingLicense table. There is more than one record in the PersonnelDrivingLicense table related to one Personnel.
I tried to get Personnel and PersonnelDrivingLicense data with linq but I am getting 2 record instead 1.
Here is my linq query:
from p in Personnel
join pdl in PersonnelDrivingLicense on p.Id equals pdl.PersonnelId
select new Personnel
{
Id = p.Id,
PersonnelDrivingLicense = new List<PersonnelDrivingLicense>
{
new PersonnelDrivinLicense
{
Id = pdl.Id,
DrivingLicenseClass = pdl.DrivingLicenseClass
}
}
}
This linq returns below result:
Id: 1,
PersonnelDrivingLicense:
Id: 1,
DrivingLicenseClass: B
Id: 1,
PersonnelDrivingLicense:
Id: 2,
DrivingLicenseClass: C
The correct result should be below:
Id: 1,
PersonnelDrivingLicense:
Id: 1,
DrivingLicenseClass: B
Id: 2,
DrivingLicenseClass: C
How can I get desired result above?
How should I write correct linq query?
Thanks.
You should group the returned Personnel objects by Id. Try this:
from p in Personnel
join pdl in PersonnelDrivingLicense on p.Id equals pdl.PersonnelId
group p by p.Id into g
select new Personnel
{
Id = g.Key,
PersonnelDrivingLicense = g.Select(x => x.PersonnelDrivingLicense).ToList()
}
If you have a one-to-many or a many-to-many relationship, and you want an item with their sub-items, you should use GroupJoin instead of Join.
In you case, you have Personnel and PersonnelDrivingLicenses, probably a one-to-many relation: every Personnel object has zero or more PersonnelDrivingLicences. Every PersonnelDrivingLicence belongs to exactly one Personnel object, namely the Personnel that the foreign key PersonnelId refers to.
Apparently you want a sequence of Personnel objects, each Personnel object with a list of his/her PersonnelDrivingLicenses.
// GroupJoin Personnel with PersonnelDrivingLicenses
var personnelWithTheirDrivingLicenses = myDbContext.Personnel
.GroupJoin(myDbDcontext.PersonnelDrivingLicenses,
// from every personnel object take the Id,
personnel => personnel.Id,
// from every driving license take the PersonnelId
personnelDrivingLicence => personnelDrivingLicence.PersonnelId,
// Take the Personnel, with all his matching driving licenses to make a new:
(personnel, drivingLicenses) => new
{
// for optimal efficiency, Select only the properties you plan to use:
Id = personnel.Id,
Name = personnel.Name,
...
DrivingLicenses = drivingLicenses
.Where(drivingLicense => ...) // only if you don't want all his DrivingLicenses
.Select(drivingLicense => new
{
// again, select only the properties you plan to use:
Id = drivingLicense.Id,
Type = drivingLicense.Type,
...
// not needed, you already know the value:
// PersonnelId = drivingLicense.PersonnelId,
})
.ToList(),
});
I can see many examples on this site of the sort of queries I'm after, but I can't relate to them and how they work. I was wondering if you could help me.
I have set up my many-to-many tables and relationships with entity designer in Visual Studio.
tblQuotes
ID | QuoteNo | Date
tblItems
ID | PartNo | Desc
tblSuppliers
ID | Supplier | email
tblQIS (quotes items suppliers)
ID | SupplierID | QuoteID | ItemID
I've put some test data in and have begun to try to type this, but I think I first need to group by quoteNo then group by supplier, to get the details in the correct view.
var tblQuotes = from d in db.tblQuotes_Items_Suppliers
.Include(t => t.tblItems)
.Include(t => t.tblQuotes)
.Include(t => t.tblSuppliers)
group by (d.QuoteID,d.SupplierID)
select d;
Can anyone help me out?
you could try this:
var tblQuotes =
from d in db.tblQuotes_Items_Suppliers // or tblQIS whatever the name
group d by new
{
d.QuoteID,
d.SupplierID
} into g
select g;
that would give you Quotes grouped by both QuoteID and SupplierID
Update
the tblQuotes is a list (IQueryable) of grouped quotes, so you can access other entities as follow:
var firstGroupOfQuotes = tblQuotes.First(); // will give you the first group of quotes
var firstQuote = firstGroupOfQuotes.First(); // will give you the first quote in the first group
var item = firstQuote.tblItems; // will give you the item of this quote
var partNo = item.PartNo; // will give you the PartNo of this item
I have table called products with columns:
productid ,
productname,
productprice
categoryid
My problem is I want to get the number of products depending on product name along with details. I want to show the data in DataGridView. How can I know the number of products for a single product name like below?
productid productname productavailable productprice
--------------------------------------------------------------------------
1 product A 2 products(product A) 100
2 product B 5 Products(product B) 200
Like the above table I have to display in DataGridView. I am using LINQ and C# and my DbContext name is tsgdbcontext.
Use GroupBy with a key that contains your grouping properties. Then select out the key properties along with the count of each from the grouping.
var query = tsgdbcontext.Products
.GroupBy(p => new {
p.ProductId,
p.ProductName,
p.ProductPrice
})
.Select(g => new {
g.Key.ProductId,
g.Key.ProductName,
g.Key.ProductPrice,
Available = g.Count()
});
Not sure I am understanding exactly + making some assumptions but here is an example linq query that produces a count based on some arbitrary selection criteria (id=2 and price greater than 100)...
int count = (from p in tsgdbcontext.Products
where p.productid == 2 && p.productprice > 100
select p).Count();