How to remove client side evaluation in EF Core 3 - ef-core-3.0

While migrating from Entity Framework 6 to EF Core 3, I'm hitting this error:
InvalidOperationException: Processing of the LINQ expression '(<>h__TransparentIdentifier0) => <>h__TransparentIdentifier0.grp' by 'NavigationExpandingExpressionVisitor' failed.
I believe this relates to some type of client side evaluation but I'm not sure how to fix. I essentially have this query:
var query = from s in ...
join ...
join ...
select new DTO {
Latest = (from r in _context.IndicatorCsLabUtilization
where r.LabSpaceId == s.Id
group r by r.LabSpaceId into grp
let maxDate = grp.Max(g => g.AssessmentDate)
from g in grp
where g.AssessmentDate == maxDate
select new EfficiencyAssessmentDto {
Comments = null,
Percent = g.Utilization,
When = g.AssessmentDate
}).FirstOrDefault(),
....
That "Latest" one is the part that's causing the failure. Can somebody help me understand how to fix that now broken query?

Related

Having() count of id's on joined table

I am trying to make this query in OrmLite:
select b.* from blog b
join blog_to_blog_category btbc on b.id = btbc.blog_id
join blog_category bc on btbc.blog_category_id = bc.id
where b.url like '%.com' and bc.id in (100, 583)
group by b.id
having count(distinct bc.id ) = 1
I can't figure out how to get the Having() method structured. I can see there is a Sql.CountDistinct() method but I can't figure out how to use it with Having().
I figure I need to do something along the lines of:
var q = db
.From<Blog>()
.LeftJoin<BlogToBlogCategory>()
.Join<BlogToBlogCategory, BlogCategory>()
.Where<BlogCategory>(x => Sql.In(x.Id, 100, 583))
.GroupBy<Blog>(bc => bc.Id)
.Having(x => Sql.CountDistinct("blog_category.id") == "2")
This gives error:
42883: operator does not exist: bigint = text
I can't see how to type it to take a table column name and return a number for comparison.
Is this query possible?
EDIT
I got around it by setting having expression explicitly
q.HavingExpression = $"having count(distinct {q.Table<BlogCategory>()}.{q.Column<BlogCategory>(bc => bc.Id)}) = 2";
I am still curious though if it is possible to do this with fluent api.
I've just added multiple typed table overloads for Having() in the latest v5.11.1 that's now available on MyGet which will allow you to reference a joined table properties in a typed expression, e.g:
var q = db
.From<Blog>()
.LeftJoin<BlogToBlogCategory>()
.Join<BlogToBlogCategory, BlogCategory>()
.Where<BlogCategory>(x => Sql.In(x.Id, 100, 583))
.GroupBy<Blog>(bc => bc.Id)
.Having<BlogCategory>(x => Sql.CountDistinct(x.Id) == 2)

ServiceStack.OrmLite Using Limit in SQL.In filter

I have a parent/child table setup - Items/ItemDetails. This part works:
var q = db.From<Item>(); //various where clauses based on request
items = db.Select<Item>(q);
q = q.Select(a => a.ITEM_NO);
itemDetails = db.Select<ItemDetail>(x => Sql.In(x.ITEM_NO, q));
Trying to add paging to improve the performance of this request for large data sets, I'm having trouble getting the .Limit(skip, rows) function to work in the SQL.In statement of the child table.
var q = db.From<Item>().Limit(skip, rows);
items = db.Select<Item>(q);
q = q.Select(a => a.ITEM_NO);
itemDetails = db.Select<ItemDetail>(x => Sql.In(x.ITEM_NO, q));
It works when limiting the results in the first select, but when used in the child data pull I get "Only one expression can be specified in the select list when the subquery is not introduced with EXISTS."
The SQL that comes out changes the where subquery to:
WHERE "ITEM_NO" IN (SELECT * FROM (SELECT "ITEM_NO", ROW_NUMBER() OVER
(ORDER BY "ITEM"."ITEM_NO") As RowNum
FROM "ITEM") AS RowConstrainedResult WHERE RowNum > 5 AND RowNum <= 15)
I understand the SQL error is because I am selecting more than one column in the IN clause. Is there a better way to write this to avoid the error?
Thanks
If you're using SQL Server 2012 or later you should use SqlServer2012Dialect.Provider, e.g:
container.Register<IDbConnectionFactory>(c =>
new OrmLiteConnectionFactory(connString, SqlServer2012Dialect.Provider));
Which lets OrmLite use the paging support added in SQL Server 2012 instead of resorting to use the windowing function hack required to implement paging for earlier versions of SQL Server.

how to write SQl Query to LINQ to SQL MVC entity framework

This is my sql Query:
SELECT ParkingPlaceName, NoOfParkingPlaces, COUNT(Place.ParkingAreaID) AS NoOfCarsParked, NoOfParkingPlaces-COUNT(Place.ParkingAreaID)
FROM ParkingArea
LEFT JOIN Place ON ParkingArea.ParkingAreaID = Place.ParkingAreaID
LEFT JOIN Car ON Car.CarID = Place.CarID
GROUP BY ParkingPlaceName, NoOfParkingPlaces, Place.ParkingAreaID
how to write in LINQ to SQL Query
I think you can use DefaultIfEmpty method to perform left outer join between 3 tables with let statements to deal with group results, hence the LINQ version from your SQL query should be similar (or same) like below:
var query = from pa in ParkingArea
from pl in Place.Where(x => pa.ParkingAreaID == x.ParkingAreaID).DefaultIfEmpty()
from ca in Car.Where(x => x.CarID == pl.CarID).DefaultIfEmpty()
group new { pa, pl.ParkingAreaID, ca.CarID } by new { pa.ParkingPlaceName, pa.NoOfParkingPlaces, pl.ParkingAreaID } into grp
let ParkingPlaceName = grp.Select(x => x.ParkingPlaceName)
let NoOfParkingPlaces = grp.Select(x => x.NoOfParkingPlaces)
let NoOfCarsParked = grp.Select(x => x.ParkingAreaID).Count()
select new
{
ParkingPlaceName,
NoOfParkingPlaces,
NoOfCarsParked,
AvailableParkingPlaces = NoOfParkingPlaces - NoOfCarsParked // new alias for holding substraction
};
I decided not to use join ... in ... on ... equals ... directly after first and third from clauses, since it may lead into confusion about which table instance should be handled when creating group elements after performing join.

ServiceStack.OrmLite 4.0.58 not creating proper SQL for boolean join conditions

I am attempting to join two tables using ServiceStack.OrmLite v4.0.58 but the SQL being generated for a boolean check is incorrect:
var exp = Db.From<AdjustmentRequest>()
.Join<Account>()
.LeftJoin<CardHolder>((ar, ch) => ch.IsPrimary == true && ar.AccountId == ch.AccountId)
is creating this (snippet) of SQL:
FROM "AdjustmentRequest"
INNER JOIN "Account"
ON ("Account"."Id" = "AdjustmentRequest"."AccountId")
LEFT JOIN "CardHolder"
ON ("CardHolder"."IsPrimary" AND ("AdjustmentRequest"."AccountId" = "CardHolder"."AccountId"))
You can see on the last line that the "IsPrimary" is not being compared to 1 (true).
This worked previously in 4.0.54.
The issue with a bool condition on a joined table in a JOIN expression should now be fixed in this commit.
This change is available from v4.0.59 that's now available on MyGet.

Converting a LEFT OUTER JOIN to Entity Framework

Here is a SQL Query I want to convert to EF4.3
command = database.GetSqlStringCommand(#"
select
H.AUTHENTICATION_ID,
USERNAME,
PERMISSIONS,
ORGANIZATION_IDENTIFIER,
O.ORGANIZATION_ID
from
AUTHENTICATION H
left join [AUTHORIZATION] T on H.AUTHENTICATION_ID=T.AUTHENTICATION_ID
join ORGANIZATION O on O.ORGANIZATION_ID = T.ORGANIZATION_ID
order by H.AUTHENTICATION_ID");
Here is the best LINQ I could come up with:
var query = from h in context.Authentications
join t in context.Authorizations on h.AuthenticationId equals t.Authentications.AuthenticationId
join o in context.Organizations on t.Organizations.OrganizationId equals o.OrganizationId
orderby
h.AuthenticationId
select new
{ AUTHENTICATION_ID = (Int16?)h.AuthenticationId,
h.Username,
t.Permissions,
o.OrganizationIdentifier,
OrganizationID = (Int16?)o.OrganizationId
};
I know i need to merge my first join (between Authorizations & Authentications) into, lets say x and apply DefaultIfEmpty but can't make out the syntax.
EDIT: Image for clarification:
Any help will be highly appreciated. Regards.
The basic syntax for a "left join" in Linq is like this:
from x in table1
join y in table2 on x.id equals y.id into jointable
from z in jointable.DefaultIfEmpty()
select new
{
x.Field1,
x.Field2,
x.Field3,
Field4 = z == null ? 0 : z.Field4
};
In your case, I'm a little confused because the entity relations you seem to be using in your Linq don't match the ones implied by your SQL; are the relationships here zero-or-one, zero-or-many, one-to-one, etc? Specifically, you're doing this:
from h in context.Authentications
join t in context.Authorizations on h.AuthenticationId equals t.Authentications.AuthenticationId
but your SQL implies that "Authentication" is the parent here with zero-or-more "Authorization" children, not the other way around, which would be more like:
from h in context.Authentications
from t in h.Authorizations.DefaultIfEmpty()
If you can give us a better idea of the data model and what data you expect to get out of it we can more easily explain how that query would look in Linq. Assuming that your relationships match what is implied by the SQL, you should be able to get what you want using the following Linq queries:
var query = from h in context.Authentications
from t in h.Authorizations.DefaultIfEmpty()
select new
{
h.AuthenticationId,
h.Username,
Permissions = t == null ? null : t.Permissions,
Organizations = t == null ? new EntitySet<Organization>() : t.Organizations
};
var query2 = from x in query
from o in x.organizations.DefaultIfEmpty()
select new
{
AUTHENTICATION_ID = (short?)x.AuthenticationId,
x.Username,
x.Permissions,
OrganizationIdentifier = o == null ? null : o.OrganizationIdentifier,
OrganizationID = o == null ? (short?)null : o.OrganizationID
};
Given the foreign keys that exist in the question diagram, how about something like this?
var query = from a in context.Authentications
select new
{
a.AuthenticationID,
a.Username,
a.Authorisations.Permissions ?? false,
a.Authorisations.Organisations.OrganisationIdentifier ?? 0
a.Authorisations.Organisations.OrganisationID ?? 0
};
I went ahead and moved the entire query to a Stored Procedure on the database. This solves the problem by avoiding LINQ and ObjectBuilder in the first place.

Resources