在ASP.NET Core 3.1中,CQRS在过滤场景中失败。

问题描述 投票:0回答:1

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

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

我的list方法是这样的。

    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));

默认情况下,没有任何参数,它返回所有项目,这是确定的,我也可以设置偏移量和限制,但对于场景中的 organizationId,状态和 organizationName,它失败了。

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().
c# asp.net-core cqrs
1个回答
0
投票

EF核心不知道如何正确地做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的代码,所以我不相信这是一个性能问题。

© www.soinside.com 2019 - 2024. All rights reserved.