Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
352 views
in Technique[技术] by (71.8m points)

c# - Nested filter on Data Transfer Object using OData Wep Api

I have a wep api project consumes data using odata but I'm having some problems with odata wep api.

when I execute that query

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

it gives me following error

"Message": "The query specified in the URI is not valid.", "ExceptionMessage": "The parent value for a property access of a property 'Fortuneteller' is not a single value. Property access can only be applied to a single value."

I don't want to return entity object from controller. Is there any way to filter the entity via DTO?

I'm using Repository + Service layer pattern in my project and structure of my project is like that

api controller <-> service <-> repository <-> EF

api controller

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

service

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

repository

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

DTO's

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; }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As the exception message tells you, the query that you have is invalid.

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

is equivalent to the linq expression

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

As you can see fortuneDTOs.Comments.Fortuneteller is incorrect as Comments is a collection and it doesn't have a property named 'FullName'.

You should use Any/All to filter on collections. For example, if you are trying to find all the fortunes where one of the commentators is 'some string', you can do

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

If instead you want to find out all the fortunes where all the comments are made by only one commentator 'some string', you can do

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...