The LINQ expression 'DbSet<Students>()' could not be translated - c#

I am getting below error while executing LINQ query -
The LINQ expression 'DbSet()' 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 'AsEnumerable',
'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
The issue is occurring in one of the join
var result = await (from stds in _context.Student
join depts in _context.departments on stds.DeptId equals depts.id into a
from b in a.Where(f => f.stdId == 123 && f.Premium.Value).DefaultIfEmpty()
select new StudentModel
{
stdName = b.stdName
}).ToListAsync();
I tried using ToList() and other options instead of ToListAsync() but nothing is working. Can someone help me out here?

LEFT JOIN can be expressed also by SelectMany. GroupJoin has very limited translation support.
var query =
from stds in _context.Student
from depts in _context.departments
.Where(depts => stds.DeptId == depts.id)
.Where(depts => depts.stdId == 123 && depts.Premium.Value)
.DefaultIfEmpty()
select new StudentModel
{
stdName = depts.stdName
};

Related

Error on LINQ query with sub query in left join

I was trying to do a sub query inside a left join using LINQ, it looks like this, in SQL:
SELECT fields
FROM table1 A
LEFT JOIN table2 B ON B.Establishment = A.Establishment
LEFT JOIN table3 C ON C.Vdb = B.Vdb AND C.Year = (SELECT MAX(Year) FROM table3 D WHERE D.Vdb = C.Vdb)
Using LINQ, I did the following:
var query = await (
from a in _context.Table1
join b in _context.Table2 on a.Establishment equals b.Establishment
join c0 in _context.Table3 on b.Vdb equals c0.Vdb into gGroup
from c in gGroup.Where(x => x.Year == (from c1 in _context.Table3
where c1.Vdb == x.Vdb
select c1.Year).Max()).DefaultIfEmpty()
select new
{
fields
})
.ToListAsync();
I built this code using LINQPad, so I was trying run there and everything was going fine, but when I put this code in my IDE and tried to run it I got the following error:
{
"Message": "The LINQ expression (expression here) 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 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.",
"ErrorName": "InvalidOperationException"
}
So I don't know exactly what's wrong so I can fix this, can anyone help me?
GroupJoin is almost non translatable by EF Core. Do not use this operator if you do not do simple LEFT JOIN.
I have rewritten query to use another technique which returns the same result:
var table3 = _context.Table3;
var latest =
from t in table3.Select(t => new { t.Vdb }).Distinct()
from r in table3
.Where(r => r.Vdb == t.Vdb)
.OrderByDescending(r.Year)
.Take(1)
select r;
var query =
from a in _context.Table1
join b in _context.Table2 on a.Establishment equals b.Establishment into gb
from b in gb.DefaultIfEmpty()
join c in latest on b.Vdb equals c.Vdb into gc
from c in gc.DefaultIfEmpty()
select new
{
// fields
};

How to write group join query in Entity Framewok Core 3.1 [duplicate]

This question already has answers here:
Query with `groupjoin` cannot be translated although it's documened as being supported
(4 answers)
Closed last year.
When I write the linq query like this, I get the error message
"System.InvalidOperationException: 'The LINQ expression 'DbSet()
.GroupJoin(
inner: DbSet(),
outerKeySelector: d => d.Id,
innerKeySelector: dc => dc.DeviceId,
resultSelector: (d, dc) => new {
deviceName = d.Name,
cams = dc
})' 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 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
How should I edit the code?
var query = context.Devices
.GroupJoin(context.DeviceControls,
d => d.Id,
dc => dc.DeviceId,
(d, dc) => new
{
deviceName = d.Name,
Cams = dc,
}).ToList();
EF core with .net core 3.1 will not let you do group by unless you do it client side. You need to call var query = context.Devices.ToList() and then do your group call on the query variable. Another option, if possible, is upgrading to .net 6. I think then you can do a server side group by.

SQL query to LINQ or Lambda

I have the following query
SELECT sdb.student_due_by_month_id, sdb.due_month_year, sum(sdb.due_total_month) FROM user_student ust
INNER JOIN student std ON ust.student_id = std.student_id
INNER JOIN student_due_by_month sdb ON std.student_id = sdb.student_id
WHERE ust.user_id = 2
GROUP BY sdb.student_due_by_month_id, sdb.student_due_by_month_id, sdb.due_month_year
I need to convert it to linq or a lambda expression.
I'm trying to turn him into a linq and this is what I have so far:
var user_due_month = await (from ust in _context.Users_students
join std in _context.Students on ust.student_id equals std.student_id
join sdb in _context.Students_dues_by_months on std.student_id equals sdb.student_id
where ust.user_id == user_id
group sdb by new { sdb.student_due_by_month_id, sdb.due_month_year } into g //from here i have yet to complete the linq query, help?
I don't know what would be missing to complete my linq query correctly, and also be able to pass it to a viewmodel.
Thanks a lot!!

Is the Select() method required for a LINQ query in Method Syntax? [duplicate]

I want to enable LinQ query syntax over my classes. I think query syntax is translated to method syntax, for example:
var query = from p in new Class1<Product>()
where p.Id == "1000"
select p
is translated to:
var query = new Class1<Product>().Where(p => p.Id == "1000").Select(p => p);
Then I have implemented my Class1 as:
public class Class1<T>
{
public Class1<T> Where(Expression<Func<T, bool>> expression)
{
return this;
}
public Class1<T> Select<TResult>(Func<T, TResult> expression)
{
return this;
}
}
And I have tested it with this code:
static void Main(string[] args)
{
var query = from p in new Class1<Product>()
where p.Id == "1000"
select p;
}
Then I have noticed that Select method is not called, however if I remove where clausule from LinQ Select is called:
static void Main(string[] args)
{
var query = from p in new Class1<Product>()
// where p.Id == "1000" -> commenting that Select method is called
select p;
}
Someone knows why?
Here a fiddle where you can test it: https://dotnetfiddle.net/JgxKG9
Someone knows why?
Yes, because that's what the language specification says to do. The query expression translation is all in section 7.16.2 of the C# 5 specification.
Section 7.16.2.5 explains why your initial example is incorrect - Select won't be called:
A query expression of the form
from x in e select v
is translated into
( e ) . Select ( x => v )
except when v is the identifier x, the translation is simply
( e )
For example
from c in customers.Where(c => c.City == “London”)
select c
is simply translated into
customers.Where(c => c.City == “London”)
However, that isn't the case for degenerate query expressions which are covered in 7.16.2.3 - which explains what happens when you remove your where clause:
A query expression of the form
from x in e select x
is translated into
( e ) . Select ( x => x )
The example
from c in customers
select c
Is translated into
customers.Select(c => c)
A degenerate query expression is one that trivially selects the elements of the source. A later phase of the translation removes degenerate queries introduced by other translation steps by replacing them with their source. It is important however to ensure that the result of a query expression is never the source object itself, as that would reveal the type and identity of the source to the client of the query. Therefore this step protects degenerate queries written directly in source code by explicitly calling Select on the source. It is then up to the implementers of Select and other query operators to ensure that these methods never return the source object itself.
Your understanding is little incorrect, the following query :
var query = from p in new Class1<Product>()
where p.Id == "1000"
select p
will translate to :
var query = new Class1<Product>().Where(p => p.Id == "1000");
and when you are removing the where part:
var query = from p in new Class1<Product>()
select p;
now it will be translated to something like:
var query = new Class1<Product>().Select(p=>p);
I'm pretty sure that the translation from query syntax to method syntax optimizes the call to Select away if it states an identity projection.
Since p => p would project everything to itself and the Where clause already added an abstraction layer between the source sequence and the result, this call is no longer necessary.
So
var query = from p in new Class1<Product>()
where p.Id == "1000"
select p;
is only translated to
var query = new Class1<Product>().Where(p => p.Id == "1000");
But I admit that I only guess that and am still searching for the relevant specification part.
Update: Jon was faster

Convert this NHibernate query with queryover

I have some problem to convert this NHibernate queries into the left join queryover
var query = session.Query<T>.Join(
Session.Query<RecordOrder>(),
q=>q.MiniDbName,
o=>o.DatabaseName,
(q,o)=>new{Record = q, Order = o.OrderValue})
Anyone can help me, I want this query support the left join.
The default join is an inner-join. Each of the additional join types can be specified using the methods .Inner, .Left, .Right, or .Full. For example, to left outer-join on Kittens use:
IQueryOver<Cat,Kitten> catQuery =
session.QueryOver<Cat>()
.Left.JoinQueryOver(c => c.Kittens)
.Where(k => k.Name == "Tiddles");
In your case :
var list =
session.QueryOver<RecordOrder>()
.Left.JoinQueryOver(c => c.Orders).ToList()

Categories

Resources