【问题标题】:CQRS is failing in filtering scenario in ASP.NET Core 3.1CQRS 在 ASP.NET Core 3.1 中的过滤场景中失败
【发布时间】:2020-05-19 08:55:50
【问题描述】:

在我的 ASP.NET Core 3.1 项目中,我使用的是 CQRS 模式。

我列出了所有带有查询参数的项目。对于限制和偏移,它正在工作,但对于其他属性,它会引发服务器错误。

我的列表方法如下:

    public class List
    {
        public class ProjectList
        {
            public List<ProjectForListDto> Projects { get; set; }
        }

        public class Query : IRequest<ProjectList>
        {
            public Query(int? limit, int? offset, string organizationName, int? organizationId, string status)
            {
                Limit = limit;
                Offset = offset;
                OrganizationName = organizationName;
                OrganizationId = organizationId;
                Status = status;
            }

            public int? Limit { get; set; }
            public int? Offset { get; set; }
            public string OrganizationName { get; set; }
            public int? OrganizationId { get; set; }
            public string Status { get; set; }
        }

        public class Handler : IRequestHandler<Query, ProjectList>
        {
            private readonly DataContext _context;
            private readonly IMapper _mapper;

            public Handler(DataContext context, IMapper mapper)
            {
                _context = context;
                _mapper = mapper;
            }

            public async Task<ProjectList> Handle(Query request, CancellationToken cancellationToken)
            {
                var queryable = _context.Projects
                                        .AsQueryable();

                if (!string.IsNullOrEmpty(request.OrganizationName) || 
                                          request.OrganizationId > 0 ||
                                          !string.IsNullOrEmpty(request.Status))
                {
                    queryable = queryable.Where(x =>
                        x.Organization.Name == request.OrganizationName ||
                        x.OrganizationId == request.OrganizationId || x.Status.ToString("G") 
               == request.Status);
                }

                var projects = await queryable.Skip(request.Offset ?? 0)
                                              .Take(request.Limit ?? 50)
                                              .ToListAsync(cancellationToken: cancellationToken);

                return new ProjectList
                {
                    Projects = _mapper.Map<List<Project>, List<ProjectForListDto>>(projects)
                };
            }
        }
    }

我的控制器操作:

[HttpGet]
public async Task<ActionResult<List.ProjectList>> List(int? offset, int? limit, 
        string organizationName, int? organizationId, string status) => await 
        Mediator.Send(new List.Query(limit, offset, organizationName, organizationId, status));

默认情况下,没有任何参数,它返回所有项目都可以,我也可以设置偏移量和限制,但是对于场景组织 ID、状态和组织名称,它会失败。 我得到的异常:

fail: API.Middleware.ErrorHandlingMiddleware[0]
      SERVER ERROR
System.InvalidOperationException: The LINQ expression 'DbSet<Project>
    .Join(
        outer: DbSet<Organization>, 
        inner: p => EF.Property<Nullable<int>>(p, "OrganizationId"), 
        outerKeySelector: o => EF.Property<Nullable<int>>(o, "Id"), 
        innerKeySelector: (o, i) => new TransparentIdentifier<Project, Organization>(
            Outer = o, 
            Inner = i
        ))
    .Where(p => p.Inner.Name == __request_OrganizationName_0 || (Nullable<int>)p.Outer.OrganizationId == __request_OrganizationId_1 || p.Outer.Status.ToString("G") == __request_Status_2)' 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().

【问题讨论】:

  • 我的猜测是 ToString("G") 无法转换为 SQL 查询。如果是这样,你必须重新设计这部分。
  • @WiktorZychla 我也尝试过不使用 ToString("G"),但我在组织名称场景中也失败了,这是纯字符串
  • 有什么例外?
  • @WiktorZychla 有问题的问题请查看异常
  • @WiktorZychla 非常感谢我在 int for status 更改为 enum 之前使用它并且它起作用了

标签: c# asp.net-core cqrs


【解决方案1】:

EF Core 目前不知道如何正确执行 GROUP JOIN。执行查询后,我必须在代码中对返回的结果集手动执行组加入。

在我编写的天气预报示例中,我必须执行以下操作才能执行群组加入:

var locationForecasts = await locations.Join(inner: forecasts,
    outerKeySelector: location => location.Id,
    innerKeySelector: forecast => forecast.LocationId,
    resultSelector: (location, forecast) =>
        new
        {
            location,
            forecast
        }).ToListAsync();

var result = locationForecasts.GroupBy(x => x.location.Id)
    .Select(x => new WeatherForecast
    {
        LocationId = x.Key,
        LocationName = x.FirstOrDefault().location.LocationName,
        Forecasts = x.Select(y => y.forecast)
    }).FirstOrDefault();

这里的重点是在SQL中执行一次JOIN,然后返回结果,然后在应用层执行GroupBy。

希望 EF 很快会支持这一点,但与此同时,这是我一直在使用的解决方法。无论如何,物化 SQL 查询似乎为 Join 和 GroupJoin 吐出相同的代码,所以我不认为这是性能问题。

【讨论】:

    猜你喜欢
    • 2020-05-04
    • 2020-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 2021-07-21
    • 1970-01-01
    相关资源
    最近更新 更多