.Net MVC Linq query - entity-framework

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.

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

Linq Join on Lists produces a list of duplicate data

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!

How do you join two many to many tables in Entity Framework?

I have a few Tables I want to join together:
Users
UserRoles
WorkflowRoles
Role
Workflow
The equivalent sql I want to generate is something like
select * from Users u
inner join UserRoles ur on u.UserId = ur.UserId
inner join WorkflowRoles wr on wr.RoleId = ur.RoleId
inner join Workflow w on wr.WorkflowId = w.Id
where u.Id = x
I want to get all the workflows a user is part of based on their roles in one query. I've found that you can get the results like this:
user.Roles.SelectMany(r => r.Workflows)
but this generates a query for each role which is obviously less than ideal.
Is there a proper way to do this without having to resort to hacks like generating a view or writing straight sql?
You could try the following two queries:
This one is better readable, I think:
var workflows = context.Users
.Where(u => u.UserId == givenUserId)
.SelectMany(u => u.Roles.SelectMany(r => r.Workflows))
.Distinct()
.ToList();
(Distinct because a user could have two roles and these roles may contain the same workflow. Without Distinct duplicate workflows would be returned.)
But this one performs better, I believe:
var workflows = context.WorkFlows
.Where(w => w.Roles.Any(r => r.Users.Any(u => u.UserId == givenUserId)))
.ToList();
So it turns out the order which you select makes the difference:
user.Select(x => x.Roles.SelectMany(y => y.Workflows)).FirstOrDefault()
Have not had a chance to test this, but it should work:
Users.Include(user => user.UserRoles).Include(user => user.UserRole.WorkflowRoles.Workflow)
If the above is not correct then is it possible that you post your class structure?

Convert this SQL to lambda for EF 4 Code first

I have this Sql statement
SELECT * FROM Game
INNER JOIN Series ON Series.Id = Game.SeriesId
INNER JOIN SeriesTeams ON SeriesTeams.SeriesId = Series.Id
INNER JOIN Team ON Team.Id = SeriesTeams.TeamId
INNER JOIN TeamPlayers ON TeamPlayers.TeamId = Team.Id
INNER JOIN Player ON Player.Id = TeamPlayers.PlayerId
WHERE AND Game.StartTime >= GETDATE()
AND Player.Id = 1
That I want to be converted into a lambda expression.
This is how it works.
A game can only be joined to 1 series, but a serie can of course have many games. A serie can have many teams and a team can join many series.
A player can play in many teams and a team has many players.
SeriesTeams and TeamPlayers are only the many-to-many tables created by EF to hold the references between series/teams and Teams/Players
Thanks in advance...
Edit: I use the EF 4 CTP5 and would like to have the answer as lambda functions, or in linq if that is easier...
Ok, first of all, if you want to make sure that everything is eager-loaded when you run your query, you should add an explicit Include:
context.
Games.
Include(g => g.Series.Teams.Select(t => t.Players)).
Where(g =>
g.StartTime >= DateTime.Now &&
g.Series.Teams.Any(t => t.Players.Any(p => p.Id == 1))).
ToList();
However, as I mentioned in my comment, this won't produce the same results as your SQL query, since you don't filter out the players from the child collection.
EF 4.1 has some nifty Applying filters when explicitly loading related entities features, but I couldn't get it to work for sub-sub-collections, so I think the closest you can get to your original query would be by projecting the results onto an anonymous object (or you can create a class for that if you need to pass this object around later on):
var query = context.
Games.
Where(g =>
g.StartTime >= DateTime.Now &&
g.Series.Teams.Any(t => t.Players.Any(p => p.Id == 1))).
Select(g => new
{
Game = g,
Players = g.
Series.
Teams.
SelectMany(t => t.
Players.
Where(p => p.Id == user.Id))
});
Then you can enumerate and inspect the results:
var gamesAndPlayersList = query.ToList();
I did found the solution.
IList<Domain.Model.Games> commingGames = this.Games
.Where(a => a.StartTime >= DateTime.Now && a.Series.Teams.Any(t => t.Players.Any(p => p.Id == user.Id))).ToList();
If somebody has a better solution then I am all ears..

Entity Sql for a Many to Many relationship

Consider two tables Bill and Product with a many to many relationship. How do you get all the bills for a particular product using Entity Sql?
Something like this
SELECT B FROM [Container].Products as P
OUTER APPLY P.Bills AS B
WHERE P.ProductID == 1
will produce a row for each Bill
Another option is something like this:
SELECT P, (SELECT B FROM P.Bills)
FROM [Container].Products AS P
WHERE P.ProductID == 1
Which will produce a row for each matching Product (in this case just one)
and the second column in the row will include a nested result set containing the bills for that product.
Hope this helps
Alex
You need to use some linq like this;
...
using (YourEntities ye = new YourEntities())
{
Product myProduct = ye.Product.First(p => p.ProductId = idParameter);
var bills = myProduct.Bill.Load();
}
...
This assumes that you have used the entitiy framework to build a model for you data.
The bills variable will hold a collection of Bill objects that are related to your product object.
Hope it helps.