简体   繁体   English

我在 C# 的实体框架中的查询出错

[英]Error in my query in Entity Framework in C#

I have a problem on my code.我的代码有问题。 I created the query below:我在下面创建了查询:

var query = from s in _context.Stores
            join co in _context.Countries on s.CountryId equals co.CountryId
            join ci in _context.Cities on s.CityId equals ci.CityId
            let categories = (from category in _context.Categories
                              join sc in _context.StoresCategories on s.StoreId equals sc.StoreId
                              where category.CategoryId == sc.CategoryId
                              select category.Description)
            let categoriesIds = (from cat in _context.Categories
                                 join sc in _context.StoresCategories on s.StoreId equals sc.StoreId
                                 where cat.CategoryId == sc.CategoryId
                                 select cat.CategoryId)
            select new Response.StoreResponse
                   {
                        StoreId = s.StoreId,
                        Name = s.Name,
                        Email = s.Email,
                        Phone = s.Phone,
                        CountryId = co.CountryId,
                        Country = co.Name,
                        CityId = ci.CityId,
                        City = ci.Name,
                        Categories = string.Join(",", categories),
                        CategoriesIds = string.Join(",", categoriesIds),
                        //Categories = categories.ToList(),
                        //CategoriesIds = categoriesIds.ToList(),
                        Logo = s.profile_url
                    };
List<Response.StoreResponse> resp = query.ToList<Response.StoreResponse>();

But I get this error:但我得到这个错误:

System.InvalidOperationException: The query contains a projection '<>h__TransparentIdentifier2 => DbSet().Join( inner: DbSet(), outerKeySelector: cat => <>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.s.StoreId, innerKeySelector: sc => sc.StoreId, resultSelector: (cat, sc) => new { cat = cat, sc = sc }).Where(<>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.cat.CategoryId == <>h__TransparentIdentifier0.sc.CategoryId).Select(<>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.cat.CategoryId)' of type 'IQueryable'. System.InvalidOperationException:查询包含投影 '<>h__TransparentIdentifier2 => DbSet().Join( inner: DbSet(), outerKeySelector: cat => <>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.s.StoreId, innerKeySelector: sc => sc.StoreId, resultSelector: (cat, sc) => new { cat = cat, sc = sc }).Where(<>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.cat.CategoryId == <>h__TransparentIdentifier0.sc。 CategoryId).Select(<>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.cat.CategoryId)' 类型为“IQueryable”。 Collections in the final projection must be an 'IEnumerable' type such as 'List'.最终投影中的 Collections 必须是“IEnumerable”类型,例如“List”。 Consider using 'ToList' or some other mechanism to convert the 'IQueryable' or 'IOrderedEnumerable' into an 'IEnumerable'.考虑使用“ToList”或其他机制将“IQueryable”或“IOrderedEnumerable”转换为“IEnumerable”。 at Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormalizingExpressionVisitor.VerifyReturnType(Expression expression, ParameterExpression lambdaParameter) at Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormalizingExpressionVisitor.VerifyReturnType(Expression expression, ParameterExpression lambdaParameter) at Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormalizingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes) at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node) at Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormal在 Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormalizingExpressionVisitor.VerifyReturnType(表达式表达式,ParameterExpression lambdaParameter) 在 Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormalizingExpressionVisitor.VerifyReturnType(表达式表达式,ParameterExpression lambdaParameter) 在 Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormalizingExpressionVisitor.VisitMethodCall (MethodCallExpression methodCallExpression) at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes) at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression 节点) 在 Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormal izingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.NormalizeQueryableMethod(Expression expression) at Microsoft.EntityFrameworkCore.Query.RelationalQueryTranslationPreprocessor.NormalizeQueryableMethod(Expression expression) at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(Expression query) at Microsoft.EntityFrameworkCore.Query.RelationalQueryTranslationPreprocessor.Process(Expression query) at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query) at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async) at Microsoft.EntityFramewo izingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.NormalizeQueryableMethod(Expression expression) at Microsoft.EntityFrameworkCore.Query.RelationalQueryTranslationPreprocessor.NormalizeQueryableMethod(Expression expression) 在 Microsoft.EntityFrameworkCore.Query.QueryCompilationContext 在 Microsoft.EntityFrameworkCore.Query.RelationalQueryTranslationPreprocessor.Process(Expression query) 在 Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(Expression query)。 Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult] 上的 CreateQueryExecutor[TResult](表达式查询)(表达式查询,Boolean 异步)在 Microsoft.EntityFramewo rkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0 1.<Execute>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func 1 compiler) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable 1.GetEnumerator() at System.Collections.Generic.List 1..ctor(IEnumerable 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable 1 source) at Store.API.Controllers.StoreController.SearchStores(StoreListRequest request) in D:\ rkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase 数据库,表达式查询,IModel model,Boolean async) 在 Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__ 1.<Execute>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func 1 compiler) 在 Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query) 在 Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider。在 Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable 1.GetEnumerator() at System.Collections.Generic.List 1..ctor(IEnumerable 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable 1 源)在 D:\ Projects\ViewInStore\src\Store.API\Controllers\StoreController.cs:line 230 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.Con Projects\ViewInStore\src\Store.API\Controllers\StoreController.cs:line 230 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft. AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) 在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) 在 Microsoft.AspNetCore.Mvc.Infrastructure.Con trollerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.A trollerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() 来自 MicrosoftAsp 的网络跟踪结束。 Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)在 Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) 在 Microsoft.A spNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context) spNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware .Invoke(HttpContext 上下文)

Thanks Alessandro谢谢亚历山德罗

One potential issue I can see will be attempting to do the string.Join 's within the Linq expression.我可以看到的一个潜在问题是尝试在 Linq 表达式中执行string.Join

Firstly, I would recommend reading up on navigation properties with EF.首先,我建议阅读 EF 的导航属性。 It is very common for developers accustomed to writing SQL / Stored Procedures / Views looking at EF and Linq to start essentially reproducing their SQL in Linq QL. It is very common for developers accustomed to writing SQL / Stored Procedures / Views looking at EF and Linq to start essentially reproducing their SQL in Linq QL. You have a Store entity, and StoreCategory, and Category which is enough to establish the many-to-many relationship between these entities.您有一个 Store 实体、StoreCategory 和 Category,它们足以在这些实体之间建立多对多关系。

Assuming EF Core 5:假设 EF Core 5:

public class Store
{
    // ... Store fields.
    public virtual City City { get; set; }
    public virtual Country Country { get; set; }
    public virtual ICollection<Category> Categories { get; set; } = new List<Category>();
}

Then in your configuration, if you don't have these wired up already: (Ie OnModelCreating or EntityTypeConfiguration)然后在您的配置中,如果您还没有这些连接:(即 OnModelCreating 或 EntityTypeConfiguration)

modelBuiler.Entity<Store>()
    .HasRequired(x => x.City)
    .WithMany()
    .HasForeignKey("CityId");
// Do the same as above for Country...

modelBuiler.Entity<Store>()
    .HasMany(x => x.Categories)
    .WithMany()
    .UsingEntity<StoreCategory>(
        x => x.HasOne(sc => sc.Store).WithMany().HasForeignKey(sc => sc.StoreId),
        x => x.HasOne(sc => sc.Category).WithMany().HasForeignKey(sc => sc.CategoryId));             

If you're using an earlier version of EF Core then the relationship has to be done through Store.StoreCategories with a many-to-one-to-many relationship.如果您使用的是早期版本的 EF Core,则必须通过具有多对一多关系的 Store.StoreCategories 完成关系。

From here instead of that Linq expression you can simplify it to use the navigation properties.从这里而不是那个 Linq 表达式,您可以简化它以使用导航属性。 However, we should avoid doing the string.Join in something that will need to be translated into SQL.但是,我们应该避免在需要翻译成 SQL 的东西中使用 string.Join。 For the Categories we project the details we need into a child response object:对于类别,我们将所需的详细信息投射到子响应 object 中:

var query = _context.Stores
    .Select(s => new Response.StoreResponse
    {
        StoreId = s.StoreId,
        Name = s.Name,
        Email = s.Email,
        Phone = s.Phone,
        CountryId = s.Country.CountryId,
        Country = s.Country.Name,
        CityId = s.City.CityId,
        City = s.City.Name,
        Categories = s.Categories
            .Select(c => new Response.CategoryResponse {c.CategoryId, c.Description})
            .ToList(),
        Logo = s.profile_url
    });
var resp = query.ToList();

This means declaring a new simple POCO for Categories in your Response namespace:这意味着在您的响应命名空间中为类别声明一个新的简单 POCO:

[Serializable] 
public class CategoryResponse
{
    public int CategoryId { get; set; }
    public int Description { get; set; }
}

Then in your Company Response class you can handle provisioning the Categories in a comma-delimited list for your consumer (view etc.), or just let your consumer format the data:然后在您的公司响应 class 中,您可以为您的消费者(查看等)处理以逗号分隔的列表中的类别配置,或者让您的消费者格式化数据:

public class CompanyResponse
{
    public ICollection<CategoryResponse> Categories { get; set; } = new List<CategoryResponse>();
    public string CategoryIds 
    {
        if (Categories == null) return null;
        return string.Join(",", categories.Select(x => x.CategoryId));
    }
    public string CategoryDescriptions 
    {
        if (Categories == null) return null;
        return string.Join(",", categories.Select(x => x.Description));
    }
}

The caveat of formatting in the view model / DTO (Response) is that it doubles up the amount of data being serialized.在视图 model / DTO(响应)中格式化的警告是它使被序列化的数据量加倍。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM