Linq Join on Lists produces a list of duplicate data - entity-framework

Hi I have a puzzling issue(to me at leaast).
I am using the latest Entity Framework on NetCore 2
So I created these 2 lists like this:
var cYear = await _context.CYear
.Where(c => c.Discriminator == 'C').ToListAsync();
var modCurricula = await _context.ModCurricula
.Where(m => m.ProductionStatus == 1.ToListAsync();
Stepping through the code, I can see that the lists contain the needed data.
But I need to join the two lists together using a Linq query to get the result set that I need:
var historicalYears = (from mc in modCurricula
join cy in cYear on mc.GroupId equals cy.GroupId
where cy.CYear == 1810
select mc.ModId).ToList();
However, when I do this, I get a list of 20 rows but each row is just the same data, like this:
20384 | 04722811
20384 | 04722811
20384 | 04722811
// etc...
So I tried joining the actual entity framework DbSet objects like this:
var historicalYears = (from mc in _context.ModCurricula
join cy in _context.CYear on mc.GroupId equals cy.GroupId
where cy.CYear == 1810
select mc.ModId).ToList();
And it works! I get the results I need, not just a list of duplicates.
Is there a reason why I'm getting duplicates using the first Linq query?
Thanks!

Related

How to get count from rows in Linq faster

I have a linq to get all row count group by Id.
Because of my table is very big it needs very long in Linq (because I have to get the data completly since EF Core 3.0).
var reportCountData = this.context.ReportData.AsEnumerable().GroupBy(x => x.ReportId).ToDictionary(x => x.Key, x => x.Count());
How to make this faster (e.g. without getting all data first)?
The following should be translated:
var reportCountData = from p in this.context.ReportData
group p by p.ReportId into g
select new
{
g.Key,
Count = g.Count()
};
https://learn.microsoft.com/de-de/ef/core/querying/complex-query-operators#groupby

.Net MVC Linq query

In my program i have a database with a table containing persons.
Every person has a collection of clothes, which has a collection of fabrics. Say i want to return the number of persons who has clothes that contain cotton.
I only want to count them once even if the person has more than one clothes that contain cotton.
I tried the following and several other solutions but it didn't quite work out for me:
if ((from p in context.Persons
from c in p.Clothes
from f in c.Fabrics
select f.Name == "Cotton").Count();
{
var count = database.People
.Where(p => p.Clothes.Any(c => c.Fabrics.Any(f => f.Name == "Cotton")))
.Count();
Select all people where any of the clothes' fabrics are Cotton.

Convert SQL to LINQ, nested select, top, "distinct" using group by and multiple order bys

I have the following SQL query, which I'm struggling to convert to LINQ.
Purpose: Get the top 10 coupons from the table, ordered by the date they expire (i.e. list the ones that are about to expire first) and then randomly choosing one of those for publication.
Notes: Because of the way the database is structured, there maybe duplicate Codes in the Coupon table. Therefore, I am using a GROUP BY to enforce distinction, because I can't use DISTINCT in the sub select query (which I think is correct). The SQL query works.
SELECT TOP 1
c1.*
FROM
Coupon c1
WHERE
Code IN (
SELECT TOP 10
c2.Code
FROM
Coupon c2
WHERE
c2.Published = 0
GROUP BY
c2.Code,
c2.Expires
ORDER BY
c2.Expires
)
ORDER BY NEWID()
Update:
This is as close as I have got, but in two queries:
var result1 = (from c in Coupons
where c.Published == false
orderby c.Expires
group c by new { c.Code, c.Expires } into coupon
select coupon.FirstOrDefault()).Take(10);
var result2 = (from c in result1
orderby Guid.NewGuid()
select c).Take(1);
Here's one possible way:
from c in Coupons
from cs in
((from c in coupons
where c.published == false
select c).Distinct()
).Take(10)
where cs.ID == c.ID
select c
Keep in mind that LINQ creates a strongly-typed data set, so an IN statement has no general equivalent. I understand trying to keep the SQL tight, but LINQ may not be the best answer for this. If you are using MS SQL Server (not SQL Server Compact) you might want to consider doing this as a Stored Procedure.
Using MercurioJ's slightly buggy response, in combination with another SO suggested random row solution my solution was:
var result3 = (from c in _dataContext.Coupons
from cs in
((from c1 in _dataContext.Coupons
where
c1.IsPublished == false
select c1).Distinct()
).Take(10)
where cs.CouponId == c.CouponId
orderby _dataContext.NewId()
select c).Take(1);

Dynamic Query with Entity Framework 4

Okay I'm new to EF and I'm having issues grasping on filtering results...
I'd like to emulate the ef code to do something like:
select *
from order o
inner join orderdetail d on (o.orderid = d.orderid)
where d.amount > 20.00
just not sure how this would be done in EF (linq to entities syntax)
Your SQL gives multiple results per order if there's multiple details > 20.00. That seems wrong to me. I think you want:
var q = from o in Context.Orders
where o.OrderDetails.Any(d => d.Amount > 20.00)
select o;
I would do it like that:
context.OrderDetails.Where(od => od.Amount > 20).Include("Order").ToList().Select(od => od.Order).Distinct();
We are taking details first, include orders, and take distinct orders.

simple LINQ query

i am having trouble joinging tables on a LINQ query.
(source: kalleload.net)
As you can see there are three tables there. On my webpage, i want to display the following data in a List View.
betid | bet.title | bet.description | match.location | match.begindate/enddate | teamone NAME | teamtwo Name.
so let me explain this.
I want 3 fields from the bets table.
I want 2 fields from the match table (where the match.matchid = bet.matchid)
I want 2 fields from the TEAM table (where match.teamone = team.teamid and match.teamtwo = team.teamid)
i hope this makes sense.
thankyou
It looks like you already have the relationships defined. If you are using the designer, you should have existing entities in the generated classes.
var result = bet.Select( b => new {
BetID = b.betid,
Title = b.title,
Description = b.description,
BeginDate = b.match.begindate,
EndDate = b.match.enddate,
TeamOneName = b.match.team_1.teamname,
TeamTwoName = b.match.team_2.teamname
} );
Note that I'm only guessing at the association names. You should be able to figure out the names given to them by the designer.
The key to this one is to include a self join on the team table, for team one and team two, like this:
var result = from bet in db.bet
join match in db.match on bet.matchid equals match.matchid
join team1 in db.team on match.teamone equals team1.teamid
join team2 in db.team on match.teamtwo equals team2.teamid
select new {bet.betid, bet.title, bet.description, match.location, match.begindate, match.enddate, team1.name, team2.name};