如果使用$ top,带有EF Core的AutoMapper无法正确返回OData @count

时间:2019-08-07 17:15:32

标签: entity-framework .net-core odata automapper

我正在使用此链接提供的解决方案:AutoMapper don't work with entity EF Core

我的问题是使用$ top时,@ odata.count总是返回$ top中通知的数字,但应返回总记录数。

我知道ODataQueryOptions具有“ Count”属性,但是我不知道是否有可能用于解决问题

我在使用ДмитрийКраснов在他的问题中提供的代码,包括Ivan Stoev的解决方案:

有实体:

public class LessonCatalog {
    public string Name { get; set; }
    public int? ImageId { get; set; }
    public virtual Image Image { get; set; }
    public virtual ICollection<Lesson> Lessons { get; set; }
}

public class Lesson {
    public string Name { get; set; }
    public string Description { get; set; }
    public int? ImageId { get; set; }
    public virtual Image Image { get; set; }
    public int LessonCatalogId { get; set; }
    public virtual LessonCatalog LessonCatalog { get; set; }
}
Views:

public class LessonView {
    public string Name { get; set; }
    public string Description { get; set; }
    public int? ImageId { get; set; }
    public ImageView Image { get; set; }
    public int LessonCatalogId { get; set; }
    public LessonCatalogView LessonCatalog { get; set; }
}

public class LessonCatalogView {
    public string Name { get; set; }
    public int? ImageId { get; set; }
    public ImageView Image { get; set; }
    public IEnumerable<LessonView> Lessons { get; set; }
}

我的地图:

CreateMap<LessonCatalog, LessonCatalogView>()
            .ForMember(dest => dest.Image, map => map.ExplicitExpansion())
            .ForMember(dest => dest.Lessons, map => map.ExplicitExpansion());

CreateMap<Lesson, LessonView>()
             .ForMember(dest => dest.LessonCatalog, map => map.ExplicitExpansion());
In my repository:

protected readonly DbContext _context;
protected readonly DbSet<TEntity> _entities;

    public Repository(DbContext context) {
        _context = context;
        _entities = context.Set<TEntity>();
    }

public IEnumerable<TView> GetOData<TView>(ODataQueryOptions<TView> query,
        Expression<Func<TEntity, bool>> predicate = null) {

        IQueryable<TEntity> repQuery = _entities.AsQueryable();
        IQueryable res;
        if (predicate != null) repQuery = _entities.Where(predicate);

        if (query != null) {
            string[] expandProperties = GetExpands(query);
            //!!!
            res = repQuery.ProjectTo<TView>(Mapper.Configuration, null, expandProperties);
            //!!!
            var settings = new ODataQuerySettings();
            var ofilter = query.Filter;
            var orderBy = query.OrderBy;
            var skip = query.Skip;
            var top = query.Top;

            if (ofilter != null) res = ofilter.ApplyTo(res, settings);
            if (orderBy != null) res = orderBy.ApplyTo(res, settings);
            if (skip != null) res = skip.ApplyTo(res, settings);
            if (top != null) res = top.ApplyTo(res, settings);
        } else {
            res = repQuery.ProjectTo<TView>(Mapper.Configuration);
        }

        return (res as IQueryable<TView>).AsEnumerable();
    }

如果我的查询结果有1007条记录,并且我使用

…$count=true&$top=5

计数结果应该是

"@odata.count": 1007

但是结果始终是

"@odata.count": 5

使用SQL Server配置文件,我可以看到“选择计数”中包括“顶部”。那么,如何避免这种情况发生?

1 个答案:

答案 0 :(得分:0)

我得到了Github Guy的帮助(感谢@Gennady Pundikov),现在可以回答这个问题。

在应用其他设置之前,我更改了GetOData方法以获取Count:

public IEnumerable<TView> GetOData<TView>(ODataQueryOptions<TView> query,
        Expression<Func<TEntity, bool>> predicate = null) {

        IQueryable<TEntity> repQuery = _entities.AsQueryable();
        IQueryable res;
        if (predicate != null) repQuery = _entities.Where(predicate);

        if (query != null) {
            string[] expandProperties = GetExpands(query);
            //!!!
            res = repQuery.ProjectTo<TView>(Mapper.Configuration, null, expandProperties);
            //!!!
            var settings = new ODataQuerySettings();
            var ofilter = query.Filter;
            var orderBy = query.OrderBy;
            var skip = query.Skip;
            var top = query.Top;

            if (ofilter != null) res = ofilter.ApplyTo(res, settings);
            if (query.Count?.Value == true)
            {
                // We should calculate TotalCount only with filter
                // http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part2-url-conventions.html#_Toc371341773
                // 4.8 Addressing the Count of a Collection
                // "The returned count MUST NOT be affected by $top, $skip, $orderby, or $expand.
                query.Request.ODataFeature().TotalCount = ((IQueryable<TView>)res).LongCount();
            }

            if (top != null) res = top.ApplyTo(res, settings);
            if (orderBy != null) res = orderBy.ApplyTo(res, settings);
            if (skip != null) res = skip.ApplyTo(res, settings);
        } else {
            res = repQuery.ProjectTo<TView>(Mapper.Configuration);
        }

        return (res as IQueryable<TView>).AsEnumerable();
    }