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.
Related
I have tried every variation of this query in EF Core and I cannot figure it out.
I have simplified this as such:
Invoice Table
InvoiceId
stuff
1
A
2
B
InvoiceLog Table
Id
InvoiceId
Date
PersonId
1
1
11/12/2015
1
2
2
1/20/2018
2
3
2
3/15/2019
3
Person Table
Id
Name
1
Bob
2
Steve
Here's my question
var vm = (from i in _context.Invoice
join l in _context.InvoiceLog on i.InvoiceId equals l.InvoiceId
**//this is returning multiple records, how do I return only the one with the Min(Date)**
join pl in _context.Person on l.UpdateUserId equals pl.PersonId
select new InvoiceViewModel
{
InvoiceId = i.InvoiceId,
SubmitterName = pl.FirstName + " " + pl.LastName,
}).ToList();
ex> for Invoice 2 this should return ONE InvoiceLog record with the min date 1/20/2018 and the Person Name of Steve.
This is the error I get:
System.InvalidOperationException
HResult=0x80131509
Message=Processing of the LINQ expression 'DbSet
.GroupJoin(
outer: DbSet,
inner: i => i.InvoiceId,
outerKeySelector: l => l.InvoiceId,
innerKeySelector: (i, lj) => new {
i = i,
lj = lj
})' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core.
See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information.
Source=Microsoft.EntityFrameworkCore
Instead of using join, you can use a cross-join by using from twice and filtering the second source down to the matching InvoiceLog rows and then taking the lowest one:
var vm = (from i in _context.Invoice
from l in (from l2 in _context.InvoiceLog
where i.InvoiceId == l2.InvoiceId
orderby l2.Date
select l2).Take(1)
join pl in _context.Person on l.UpdateUserId equals pl.Id
select new InvoiceViewModel {
InvoiceId = i.InvoiceId,
SubmitterName = pl.Name
}).ToList();
NOTE: EF Core 5 supports filtered include, with OrderBy and Take, so you could setup a proper relation between Invoice and InvoiceLog and then just Include what you need.
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.
I am having a "Type expected" error which I have no idea why.
My query simply link 3 tables together while trying to get the distinct package and average number of rating.
The outcome should be like this
| PackageName | Average Rating |
| SG | 4 |
| USA | 4 |
IQueryable<Recommendation> recommendationQuery = db.Recommendations;
IQueryable<Booking> bookingQuery = db.Bookings;
IQueryable<Package> packageQuery = db.Packages;
recommendationQuery = (from recommendationItem in recommendationQuery
join bookingItem in bookingQuery
on recommendationItem.BookingId equals bookingItem.BookingId
join packageItem in packageQuery
on recommendationItem.Booking.PackageId equals packageItem.PackageId
select recommendationItem).GroupBy(c => c.Booking.Package.PackageTitle)
.Select(c => new ( c.Key, c.Average(d=>d.Rating)));
The type expected occurs in the .Select(c => new (.....
May I know if I have query it wrongly?
Because
1) I inner joined all my 3 tables together
2) Assuming I have all the table joined, I tried to group them by PackageName to distinct the name to one name
3) I tried to select the average sum of the rating of the same package.
any idea if there's a better solution for this?
database class diagram
Solution error
You need to store results back into a new variable to match your new type:
var results = from recommendationItem in recommendationQuery
join bookingItem in bookingQuery
on recommendationItem.BookingId equals bookingItem.BookingId
join packageItem in packageQuery
on recommendationItem.Booking.PackageId equals packageItem.PackageId
group recommendationItem
by recommendationItem.Booking.Package.PackageTitle
into grp
select new
{
PackageName = grp.Key,
AverageRating = grp.Average(d => d.Rating)
};
I have 3 tables:
Degree(Id int(PK), DegreeName string)
1 Bachelor
2 Master
3 PhD
Track(Id int(PK), DegreeId int(FK), TrackName string)
1 2 Engineer
2 1 Technician
3 1 Assistant
4 2 Physicist
5 3 Doctor
Group(Id int(PK), TrackId int(FK), GroupName string)
1 4 Group1
2 3 Group2
3 1 Group3
4 3 Group4
5 2 Group5
there is a one to many relation between Degree and Track, and another one to many relation between Track and Group.
I have this class:
Public class DegreeDetails
{
public List<Track> TrackList { get; set; }
public List<Group> GroupsList { get; set; }
}
to get all tracks these belong to bachelor degree, which are technician and assistant, I use this code:
In the controller I use this code:
DegreeDetails MyView = new DegreeDetails();
MyView.TrackList = entity.Track.Where(s => s.DegreeID == 1).ToList();
how to get a Group List of all groups these study tracks belong to bachelor degree, which should be Group2, Group4 and Group5.
Probably the best thing to do is to join these tables. You could create a view in your database, or you can join tables using Linq.
This should work:
MyView.GroupList = (from d in entity.Degree
join t in entity.Track on d.Id equals t.DegreeId
join g in entity.Group on t.Id equals g.TrackId
where d.Id == 1
select g).Distinct().ToList();
UPDATE If you want to use lambda exp, try this:
MyView.GroupList = entity.Degree.Where(d => d.Id == 1)
.Join(entity.Track, d => d.Id, t=> t.DegreeId, (d, t) => t)
.Join(entity.Group, t => t.Id, g => g.TrackId, (t, g) => g)
.Distinct().ToList();
You should join tracks with groups:
var groupList = entity.Track.Where(s=>s.DegreeID == 1).Join(entity.Group, t=>t.Id, g=>g.TrackId, (t,g)=>g).ToArray();
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();