using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using PostAlmostAnything.Models;
using PostAlmostAnything.Data;
using Microsoft.EntityFrameworkCore;
namespace PostAlmostAnything.SiteServices
{
public class PostsService
{
private readonly ApplicationDbContext _context;
public PostsService(ApplicationDbContext context)
{
_context = context;
}
public async Task<Posts[]> GetPosts()
{
var posts = await _context.Posts
.Where(x => x.Active == true && x.Adminban == false && x.Site == GlobalStatic.SITENUMBER())
.Distinct()
.Include(p => p.CategoryNavigation)
.ThenInclude(p => p.Categoryname)
.Include(p => p.SubcategoryNavigation)
.ThenInclude(p => p.Subcategoryname)
.Include(p => p.Subcategory2Navigation)
.ThenInclude(p => p.Subcategory2name)
.Include(p => p.CityNavigation)
.ThenInclude(p => p.City)
.Include(p => p.RegionNavigation)
.ThenInclude(p => p.Regionname)
.Include(p => p.WorldareaNavigation)
.ThenInclude(p => p.Worldarea1)
.ToArrayAsync();
return posts;
}
public async Task<List<Posts>> GetPaginatedResult(int currentPage, int pageSize)
{
var data = await GetPosts();
return data.OrderByDescending(d => d.Postid).Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
}
}
}
The problem that causes the invalid Lambda error is with the addition of ThenInclude. An earlier version that only had the includes did not crash and I could access the data I wanted in my page method by writing something like:
The problem that made me seek to enhance my service class came when I could not find a way to get the same functionality in my Controller that I use so that my infinite scroll javascript can access the data via json. The controller looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using PostAlmostAnything.Data;
using PostAlmostAnything.Models;
using PostAlmostAnything.SiteServices;
namespace PostAlmostAnything.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PaginatedPostsController : ControllerBase
{
private readonly ApplicationDbContext _context;
public PaginatedPostsController(ApplicationDbContext context, PostsService postService)
{
_context = context;
PostService = postService;
}
public PostsService PostService { get; }
[HttpGet("{id:int}/{sid:int}")]
public List<Posts> GetPaginatedPosts(int id, int sid)
{
int CurrentPage = id;
int PageSize = sid;
return PostService.GetPaginatedResult(CurrentPage, PageSize).Result;
}
}
}
This setup works great if I am only trying to work with a couple of fields from the Posts table. I was able to create a home page that rendered the first 12 results using server side code and all the rest using infinite scroll. I like that combination because
Google will need to be able to read some content and the human experience is better with infinite scroll.
The solution I am looking for need to restrict what data the api tries to render in json either at the service class level or at the controller level. I would rather find a way to do it with the service so that it can be reused anytime I want to get all
the posts in a paginated format. According to the tutorial I should be able to access the related data using what I am using, so I don't see why this expression doesn't just get the name fields from tables it specifies.
This my first .Net Core project and all my previous ASP.Net experience is with WebForms up until mid-2012 before I took a break until a few months ago, so I started with this tutorial that used
this code as a model. Unfortunately that tutorial series did not use a database, so I've had to improvise since then.
Also, how do I tell GetPosts to exclude certain field? I would love to see something like "Exclude(posts.userid)"
Also, how do I tell GetPosts to exclude certain field? I would love to see something like "Exclude(posts.userid)"
The standard programming pattern to accomplish this is using a projection query to populate a ViewModel which contains only the data needed by the UI. You have to keep in mind that the DbContext is a code representation of your database tables. The project
query allow you to SELECT only the fields you want similar to crafting a SELECT using T-SQL.
The problem that causes the invalid Lambda error is with the addition of ThenInclude.
Include and ThenInclude are used for navigation properties, from the
doc:
Entity Framework Core allows you to use the navigation properties in your model to load related entities.You can use the Include method to specify related data to be included in query results.You can drill down
through relationships to include multiple levels of related data using the ThenInclude method.
In your situation, it seems that Categoryname,Subcategoryname are just property names instead of navigation properties, then the error `Lambda expression used inside Include is not valid.` occurs.
CopBlaster
The solution I am looking for need to restrict what data the api tries to render in json either at the service class level or at the controller level.
If you would like to return specific properties you could use `Select()` before `ToArrayAsync` to select what you need, refer to
The result I am looking for includes corresponding values in related tables. So if I have a posts table with a category id and I want the category name from the categories able how do I get that using linq?
The same query would also need the subcategory name from the subcategories table where the subcategory id = the subcategory id in the Posts table.
I got something working by removing all the includes and writing a select statement similar to Xing's except it looks like:
CategoryNavigation = new Categories
{
Categoryname = p.CategoryNavigation.Categoryname
},
SubcategoryNavigation = new Subcategories
{
Subcategoryname = p.SubcategoryNavigation.Subcategoryname
},
Now I need to find a way to do the same thing for public virtual ICollections. For instance if I want all of the comments for each post that is not done using navigation in the Posts table but there is a PostNavigation in the Comments table. The Posts table
refers to Comments as:
public virtual ICollection<Comments> Comments { get; set; }
Getting the Comments is easy, it is getting the comments with constraints that is hard or even telling the thing to take the first comment. Or in the example image and image name
An unhandled exception occurred while processing the request.
<div class="titleerror">InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.</div>
Microsoft.AspNetCore.Server.IIS.Core.HttpResponseStream.Write(byte[] buffer, int offset, int count)
Stack
Query
Cookies
Headers
Routing
<div id="stackpage" class="page">
InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.
Microsoft.AspNetCore.Server.IIS.Core.HttpResponseStream.Write(byte[] buffer, int offset, int count)
Microsoft.AspNetCore.Server.IIS.Core.WrappingStream.Write(byte[] buffer, int offset, int count)
Member
5 Points
209 Posts
Lambda expression used inside Include is not valid.
Oct 29, 2019 05:29 AM|CopBlaster|LINK
I followed the tutorial at https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/read-related-data?view=aspnetcore-3.0 in an effort to include linked tables in my GetPosts() results but even though I copied the structure of the query in the tutorial exactly, the result is a runtime error saying that the lambda expression is not valid. This is my service class:
The problem that causes the invalid Lambda error is with the addition of ThenInclude. An earlier version that only had the includes did not crash and I could access the data I wanted in my page method by writing something like:
The problem that made me seek to enhance my service class came when I could not find a way to get the same functionality in my Controller that I use so that my infinite scroll javascript can access the data via json. The controller looks like this:
This setup works great if I am only trying to work with a couple of fields from the Posts table. I was able to create a home page that rendered the first 12 results using server side code and all the rest using infinite scroll. I like that combination because Google will need to be able to read some content and the human experience is better with infinite scroll.
The solution I am looking for need to restrict what data the api tries to render in json either at the service class level or at the controller level. I would rather find a way to do it with the service so that it can be reused anytime I want to get all the posts in a paginated format. According to the tutorial I should be able to access the related data using what I am using, so I don't see why this expression doesn't just get the name fields from tables it specifies.
This my first .Net Core project and all my previous ASP.Net experience is with WebForms up until mid-2012 before I took a break until a few months ago, so I started with this tutorial that used this code as a model. Unfortunately that tutorial series did not use a database, so I've had to improvise since then.
Also, how do I tell GetPosts to exclude certain field? I would love to see something like "Exclude(posts.userid)"
All-Star
53711 Points
24040 Posts
Re: Lambda expression used inside Include is not valid.
Oct 29, 2019 11:43 AM|mgebhard|LINK
There's a few thing that need clarification. What is the actual error? The link query is trying to do an ADD like below.
Is this what you expect? https://docs.microsoft.com/en-us/ef/core/querying/related-data
The standard programming pattern to accomplish this is using a projection query to populate a ViewModel which contains only the data needed by the UI. You have to keep in mind that the DbContext is a code representation of your database tables. The project query allow you to SELECT only the fields you want similar to crafting a SELECT using T-SQL.
https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/query-expression-syntax-examples-projection
Contributor
2253 Points
735 Posts
Re: Lambda expression used inside Include is not valid.
Oct 31, 2019 06:04 AM|Xing Zou|LINK
Hi CopBlaster,
Include and ThenInclude are used for navigation properties, from the doc:
Entity Framework Core allows you to use the navigation properties in your model to load related entities.You can use the
Include
method to specify related data to be included in query results.You can drill down through relationships to include multiple levels of related data using theThenInclude
method.In your situation, it seems that Categoryname,Subcategoryname are just property names instead of navigation properties, then the error `Lambda expression used inside Include is not valid.` occurs.
If you would like to return specific properties you could use `Select()` before `ToArrayAsync` to select what you need, refer to
https://stackoverflow.com/questions/52205841/how-to-properly-return-a-subset-of-object-properties
For example
Best Regards,
Xing
Member
5 Points
209 Posts
Re: Lambda expression used inside Include is not valid.
Nov 15, 2019 09:23 PM|CopBlaster|LINK
Xing,
Your syntax does not work if I try to add
it says that the new CategoryNavigation cannot be found and asks if I am missing a name or assembly reference.
Member
5 Points
209 Posts
Re: Lambda expression used inside Include is not valid.
Nov 15, 2019 10:05 PM|CopBlaster|LINK
The result I am looking for includes corresponding values in related tables. So if I have a posts table with a category id and I want the category name from the categories able how do I get that using linq?
The same query would also need the subcategory name from the subcategories table where the subcategory id = the subcategory id in the Posts table.
Member
5 Points
209 Posts
Re: Lambda expression used inside Include is not valid.
Nov 15, 2019 10:42 PM|CopBlaster|LINK
I got something working by removing all the includes and writing a select statement similar to Xing's except it looks like:
Now I need to find a way to do the same thing for public virtual ICollections. For instance if I want all of the comments for each post that is not done using navigation in the Posts table but there is a PostNavigation in the Comments table. The Posts table refers to Comments as:
Member
5 Points
209 Posts
Re: Lambda expression used inside Include is not valid.
Nov 16, 2019 01:57 AM|CopBlaster|LINK
Getting the Comments is easy, it is getting the comments with constraints that is hard or even telling the thing to take the first comment. Or in the example image and image name
This returns:
An unhandled exception occurred while processing the request.
<div class="titleerror">InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.</div>Microsoft.AspNetCore.Server.IIS.Core.HttpResponseStream.Write(byte[] buffer, int offset, int count)
InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.
Microsoft.AspNetCore.Server.IIS.Core.HttpResponseStream.Write(byte[] buffer, int offset, int count)
Microsoft.AspNetCore.Server.IIS.Core.WrappingStream.Write(byte[] buffer, int offset, int count)
Microsoft.AspNetCore.WebUtilities.HttpResponseStreamWriter.FlushInternal(bool flushEncoder)
Microsoft.AspNetCore.WebUtilities.HttpResponseStreamWriter.Dispose(bool disposing)
System.IO.TextWriter.Dispose()
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0<TFilter, TFilterAsync>(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Contributor
2253 Points
735 Posts
Re: Lambda expression used inside Include is not valid.
Nov 18, 2019 05:07 AM|Xing Zou|LINK
Does the problem occur in local or IIS?Have you tried to use below code in startup:
Refer to https://github.com/aspnet/AspNetCore/issues/8302