使用 OData Web Api 对数据传输对象进行嵌套筛选

Posted

技术标签:

【中文标题】使用 OData Web Api 对数据传输对象进行嵌套筛选【英文标题】:Nested filter on Data Transfer Object using OData Wep Api 【发布时间】:2013-09-25 13:45:40 【问题描述】:

我有一个 wep api 项目使用 odata 使用数据,但我在使用 odata wep api 时遇到了一些问题。

当我执行那个查询时

/api/values?$top=50&$filter=Comments/Fortuneteller/FullName eq '一些字符串'

它给了我以下错误

"Message": "URI 中指定的查询无效。", "ExceptionMessage": "属性 'Fortuneteller' 的属性访问的父值不是单个值。属性访问只能应用于单个值。"

我不想从控制器返回实体对象。有没有办法通过 DTO 过滤实体?

我在我的项目中使用 Repository + Service 层模式,我的项目结构是这样的

api 控制器 服务 存储库 EF

api 控制器

    [Queryable]
    public IQueryable<FortuneDTO> Get()
    
        return service.FiterBy((_ => true));
    

服务

    public IQueryable<FortuneDTO> FiterBy(Expression<Func<tblFortune, bool>> filter)
    
        return repository.List().Where(filter).Select(_ => new FortuneDTO
        
            CreatedByFullName = _.aspnet_Users.FullName,
            Id = _.FortuneId,
            Comments = _.tblComment.Select(c => new CommentDTO
            
                Id=c.CommentId,
                Comment = c.Comment,
                Fortuneteller = new FortunetellerDTO  
                    FullName=c.aspnet_Users.FullName,
                    Id=c.aspnet_Users.UserId
                
            ).AsQueryable()
        );
    

存储库

    public virtual IQueryable<TEntity> List()
    
        return context.CreateObjectSet<TEntity>();
    

DTO

public class FortuneDTO

    public int Id  get; set; 
    public string CreatedByFullName  get; set; 
    public IQueryable<CommentDTO> Comments  get; set; 

public class CommentDTO

    public int Id  get; set; 
    public string Comment  get; set; 
    public FortunetellerDTO Fortuneteller  get; set; 

public class FortunetellerDTO

    public Guid Id  get; set; 
    public string FullName  get; set; 

【问题讨论】:

【参考方案1】:

正如异常消息告诉您的,您的查询无效。

/api/values?$top=50&$filter=Comments/Fortuneteller/FullName eq 'some string'

等价于linq表达式

fortuneDTOs.Where(f => f.Comments.Fortuneteller.FullName == "some string").Top(50)

如您所见,fortuneDTOs.Comments.Fortuneteller 不正确,因为 Comments 是一个集合,它没有名为“FullName”的属性。

您应该使用 Any/All 来过滤集合。例如,如果您要查找其中一位评论员是“某个字符串”的所有命运,您可以这样做

/api/values?$top=50&$filter=Comments/any(c: c/Fortuneteller/FullName eq 'some string')

如果你想找出所有的财富都是由一个评论员“一些字符串”创造的,你可以这样做

/api/values?$top=50&$filter=Comments/all(c: c/Fortuneteller/FullName eq 'some string')

【讨论】:

谢谢,我遇到了问题,但现在它给了我这个错误消息,我无法弄清楚它是什么意思 "Message": "An error has occurred.", "ExceptionMessage": " 'ObjectContent`1' 类型无法序列化内容类型 'application/json; charset=utf-8' 的响应正文。” 和内部异常“Message”:“发生错误。”,“ExceptionMessage”:“无法比较'System.Linq.IQueryable`1'类型的元素。只有原始类型(支持 Int32、String 和 Guid)和实体类型。” 如果我们想使用 contains 而不是 eq 怎么办?

以上是关于使用 OData Web Api 对数据传输对象进行嵌套筛选的主要内容,如果未能解决你的问题,请参考以下文章

在没有实体框架的情况下创建 Odata Web API 应用程序

如何获取 OData 可查询 Web API 端点过滤器并从 DTO 对象映射它?

.Net Core 3.1 Web Api 的自定义 OData 日期时间序列化程序

[转]Web Api系列教程第2季(OData篇)——使用Web Api创建只读的OData服务

ODATA WEB API----ODATA服务与客户端

带有 odata 和 $expand 的 Web Api 2.2