Linq to Entities Group by followed by Min - entity-framework

I want to write the following SQL as a Linq to Entities statement
select min(enddate), Code
from t1
inner join t2
on t1.t2id = t2.id
group by Code
What I have so far is
var data = ctx.t1.Join(ctx.t2,
one => one.t2id,
two => two.Id,
(one, two) => new {one, two})
.GroupBy(onetwo => onetwo.one.t2id)
.Min(onetwo => WHAT GOES HERE?);
I think the only thing I am missing is what goes in WHAT GOES HERE?. I could be wrong and have gone totally astray but as far as I know this is the only thing I am missing. Any idea what I can do?

What you should be using is a Select not a Min, otherwise you will only be able to return a single value. For example, something like this:
var data = ctx.t1
.Join(ctx.t2, one => one.t2id, two => two.Id, (one, two) => new {one, two})
.GroupBy(onetwo => onetwo.one.t2id)
.Select(x => new
{
Code = x.Key,
MinDate = x.Min(g => g.one.EndDate) //This may need to be g.two.EndDate
});

Related

EF Core: group by => InvalidOperationException

I'm working on kind of education project (for myself) to learn EF Core -> code first approach and I'm struggling what is wrong with my query. A have two simple entitities: article, and user and I want to group them to get an list of objects that contain list of all user with related articles.
{
var authorRowModels =
from articles in _myContext.Articles
join authors in _myContext.Users on articles.Author.Id equals authors.Id
group new { articles, authors } by authors into authorWithArticles
select new
{
AuthorFirstName = authorWithArticles.Key.FirstName,
AuthorLastName = authorWithArticles.Key.LastName,
Articles = authorWithArticles.Select(x => x.articles)
};
return View(authorRowModels.AsEnumerable().Select(x => new AuthorRowModel
{
AuthorFirstName = x.AuthorFirstName,
AuthorLastName = x.AuthorLastName,
Articles = x.Articles.ToList()
}));
}
but I'm getting an error:
InvalidOperationException: The LINQ expression 'DbSet .LeftJoin( outer: DbSet, inner: a => EF.Property<Nullable>(a, "AuthorId"), outerKeySelector: u0 => EF.Property<Nullable>(u0, "Id"), innerKeySelector: (o, i) => new TransparentIdentifier<Article, User>( Outer = o, Inner = i )) .Join( outer: DbSet, inner: a => a.Inner.Id, outerKeySelector: u => u.Id, innerKeySelector: (a, u) => new TransparentIdentifier<TransparentIdentifier<Article, User>, User>( Outer = a, Inner = u )) .GroupBy( source: ti => ti.Inner, keySelector: ti => new { articles = ti.Outer.Outer, authors = ti.Inner })' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
and I have no idea what EF not able to translate. Also if you have a hint how to rewrite this query in better way maybe even without grouping it'd be great :)
Thank you.
Using join in EF LINQ is almost always the wrong solution.
With a Navigation Property this can simply be something like:
var authorRowModels = from a in _myContext.Users
where a.Articles.Any()
select new
{
a.FirstName,
a.LastName,
a.Articles
};

How do I do an Left Outer Join in EF Core v3

I have been trying to use the GroupJoin statement to do a left outer join on two tables so that i can get a list of rows in table A which does not have any items in table B. However I keep getting an exception
Exception found: Processing of the LINQ expression 'DbSet<People>
.GroupJoin(
outer: DbSet<RiskGroup>,
inner: person => (Nullable<int>)person.Id,
outerKeySelector: risk => risk.AssessorId,
innerKeySelector: (person, risks) => new {
person = person,
risks = risks
.DefaultIfEmpty()
})' by 'NavigationExpandingExpressionVisitor' failed.
which seems to imply that it is not possible in EF Core v3. Does anyone know how to get around this problem or is my LINQ incorrect below:
var Ids = destContext.People.GroupJoin(destContext.RiskGroup,
person => person.Id,
risk => risk.AssessorId,
(person, risks) => new { person, risks = risks.DefaultIfEmpty() }).ToList();
I have trying to find all rows in the person table who doesn't have rows in the RiskGroup table.
I have struggled with this myself and I would like to see if this help you
OK for starters, I am going to keep this simple. Just find things are easier if we do
this is something that every developer comes across Company and address
the first table (Company) is the table that we could have multple records
the second table (Address) we have a single record for
company => company.AddressId,
address => address.AddressId,
So we are querying using the addressId of the address, I always used tableNameId, it makes things easier to read
So for the GroupJoin you now need output to be able to be used later in the query.
(company, address) = new (company, address)
And now you need a SelectMany - this is what screws everyone up
you need a record for when there is a null in Company
s.address.DefaultIfEmpty(),
and the output from the SelectMany
(s, address) => new { company = s.company, address });
Notice, very important - company must be s.company - not just company or the LEFT JOIN will not appear.
var a = context.Companys.GroupJoin(context.Addresses,
company => company.AddressId,
address => address.AddressId,
(company, address) => new { company, address })
.SelectMany(s => s.address.DefaultIfEmpty(),
(s, address) => new { company = s.company, address });
var outA = a.ToList();
for your specific issue
var a = destContext.People.GroupJoin(destContext.RiskGroup,
person => person.Id,
risk => risk.AssessorId,
(person, risk) => new { person, risk })
.SelectMany(s => s.risk.DefaultIfEmpty(),
(s, risk) => new { person = s.person, risk })
.Where(x => x.AssesorId == null);
var outA = a.ToList();
Try that out and see if you get what you need

Query Combinaton

I am trying to build a query using asp.net core c#
https://www.reflectionit.nl/blog/2017/paging-in-asp-net-core-mvc-and-entityframework-core
I trying to do a filtering however I need the data from another table which have my unique id
var result = _context.UserRoles.Where(y => y.RoleId.Contains(selectedRoles.Id)); // Retrieve the the userid i have from another table with the selected roleid
var query = _context.Users.Where(x => //I have already tried contains, where join );
If there is a site where i can learn this query please recommend. "Join()" does not work as I am doing paging
a least two solutions (please note that I do not check the identity classes members, so the following is the "spirit" of the solution (you miss the select clauses) ):
var result = _context.UserRoles.
Where(y => selectedRoles.Contains(y.RoleId)).
Select(y => y.User);
or
var result = _context.UserRoles.
Where(y => selectedRoles.Contains(y.RoleId)).
Select(y => y.UserId);
query = _context.Users.
Where(x => result.Contains(x.Id));
That said, assuming that there is no UserRoles table exposed in Identity (v2), you probably want:
userManager.Users.
Where(u => u.Roles.Any(r => selectecRoles.Contains(r.RoleId)));
Up to you to instanciate the userManager.

how to implement EF inner join with given filter?

SELECT DISTINCT k.* FROM [dbo].[kinds] K
INNER JOIN KindGraphic KG ON K.KindId = KG.KindId
INNER JOIN Graphics G ON KG.GraphicId = G.GraphicId
WHERE K.CategoryType = 2
AND G.IsSpecial = 1
How to write this in EF ? I am new to EF. I m using dbContex for my MVC project.
Make Note that "KindGraphic" table is mapped liked this ways
so I can not use this method https://stackoverflow.com/a/21986882/3264939
modelBuilder.Entity<Kind>()
.HasMany(c => c.Graphics)
.WithMany(g => g.Kinds)
.Map(t => t.MapLeftKey("KindId")
.MapRightKey("GraphicId")
.ToTable("KindGraphic"));
The result from your original query is some kind of complex result. So without selecting the exact columns (instead of using *), I assume the result is contained in an anonymous type like this:
{
Kind,
Graphic
}
I understand that KindGraphic is some kind of junction (join) table, so it's info is not important to include in the result (we can access KindId from Kind and GraphicId from Graphic). Here is the LINQ query:
var result = context.kinds.Where(e => e.CategoryType == 2)
.SelectMany(e=> e.Graphics.Where(g=>g.IsSpecial == 1),
(e, g) => new { Kind = e, Graphic = g} );
After your edit to use distinct, the query can be translated as you want all kinds having category type = 2 and any Graphics with IsSpecial = 1. So it should be like this:
var result = context.kinds.Where(e => e.CategoryType == 2 &&
e.Graphics.Any(g=>g.IsSpecial == 1));

EntityFramework - how to get rows that match any of the IDS from another table where the userId matches?

I'm not sure how to get the rows I need in EF. In SQL it would look something like this:
SELECT * FROM [Recipes]
JOIN [UserFavorites] ON [UserFavorites].[RecipeId] = [Recipes].[Id]
WHERE [UserFavorites].[UserId] = #UserId
I know how to get the userfavorites that match the user id like this:
db.UserFavorites.Where(x => x.UserId == userId
But then how do I get all of the recipes that match the recipeIds inside of those userfavorites?
You can either use LINQ and construct a query:
var recipes = from r in db.Recipes
join f in db.UserFavorites on r.Id equals f.RecipeId
where f.UserId = userId
select r
or you can use the lambda syntax with navigation properties, assuming you have them set up for the relationships in question
var recipes = db.Recipes.Where(r => r.UserFavorites.Any(f => f.UserId == userId));
You can, of course, construct the actual query that's described in the first section using the equivalent lambda syntax (since the query syntax is just a language feature that compiles down to the equivalent calls to the extension methods using anonymous delegates), but that tends to be a little more difficult to read.
How about:
var recipes = context.Recipes
.SelectMany(r => r.Users, (r, u) => new { Recipe = r, User = u }
.Where(o => o.User.UserId = userId)
.Select(o => o.Recipe);
This implies UserFavorites is the intersection table between Recipes and Users
Recipes >- UserFavorites -< Users