Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/37.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net Web API可查询-如何应用AutoMapper?_Asp.net_.net_Asp.net Mvc_Asp.net Web Api - Fatal编程技术网

Asp.net Web API可查询-如何应用AutoMapper?

Asp.net Web API可查询-如何应用AutoMapper?,asp.net,.net,asp.net-mvc,asp.net-web-api,Asp.net,.net,Asp.net Mvc,Asp.net Web Api,我有这样一个简单的WebApi方法,它用ODataQueryable属性修饰 [Queryable] public virtual IQueryable<PersonDto> Get() { return uow.Person().GetAll()); // Currently returns Person instead of PersonD } [可查询] 公共虚拟IQueryable Get() { return uow.Per

我有这样一个简单的WebApi方法,它用ODataQueryable属性修饰

    [Queryable]
    public virtual IQueryable<PersonDto> Get()
    {
        return uow.Person().GetAll()); // Currently returns Person instead of PersonD
    }
[可查询]
公共虚拟IQueryable Get()
{
return uow.Person().GetAll());//当前返回的是Person而不是PersonD
}
我要做的是在WebAPI将查询结果转换为JSON之前,使用AutoMapper将查询结果从Person类型转换为PersonDto类型

有人知道我怎么做吗?我知道,我可以在GetAll()调用之后应用Mapper.Map,然后再转换回IQueryable,但是这会导致在应用OData筛选器之前返回并映射整个表(不好!)

这个问题似乎涵盖了同一个问题(参见第二个回答以获得更好的答案),其中建议在链的末尾使用AutoMapper,使用自定义MediaTypeFormatter,但是根据我看到的示例,我不知道如何做到这一点

我们将感激您的帮助

--进一步资料

我已经查看了IQueryable的源代码,但不幸的是,在那里我看不到任何为此目的使用代码的方法。我已经设法写了一个额外的过滤器,似乎工作,但它肯定不是优雅的

public class PersonToPersonDtoConvertAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
    {
        HttpResponseMessage response = actionExecutedContext.Response;

        if (response != null)
        {
            ObjectContent responseContent = response.Content as ObjectContent;
            var query = (responseContent.Value as IQueryable<Student>).ToList();
            response.Content = new ObjectContent<IEnumerable<StudentResource>>(query.ToList().Select(Mapper.Map<Person, PersonDto>), responseContent.Formatter);
        }
    }
}
公共类PersonToPersonToConvertAttribute:ActionFilterAttribute
{
公共覆盖无效OnActionExecuted(System.Web.Http.Filters.HttpActionExecuteContext ActionExecuteContext)
{
HttpResponseMessage response=actionExecutedContext.response;
if(响应!=null)
{
ObjectContent responseContent=response.Content作为ObjectContent;
var query=(responseContent.Value作为IQueryable.ToList();
response.Content=newobjectcontent(query.ToList().Select(Mapper.Map)、responseContent.Formatter);
}
}
}
然后我把动作装饰得像

    [Queryable]
    [PersonToPersonDtoConvert]
    public IQueryable<Person> Get()
    {
        return uow.GetRepo<IRepository<Person>>().GetAll();
    }
[可查询]
[PersonToConvert]
公共IQueryable Get()
{
返回uow.GetRepo().GetAll();
}

有一个更好的解决方案。试试这个:

public virtual IQueryable<PersonDto> Get(ODataQueryOptions<Person> query)
{
    var people = query.ApplyTo(uow.Person().GetAll());
    return ConvertToDtos(people);
}
公共虚拟iQueryTable获取(ODataQueryOptions查询)
{
var people=query.ApplyTo(uow.Person().GetAll());
返回Todtos(人);
}

这将确保查询在Person而不是PersonDTO上运行。如果您希望通过属性而不是代码进行转换,您仍然需要实现一个类似于您设置的操作过滤器。

IMHO接受的解决方案不正确。一般来说,如果您的服务使用DTO,那么您不希望向服务公开底层实体(个人)。为什么要查询
Person
模型并返回
PersonDTO
对象

由于您已经在使用它,Automapper提供了一个功能,允许您仅公开DTO,并将筛选应用于数据源的底层类型。例如:

public IQueryable<PersonDto> Get(ODataQueryOptions<PersonDto> options) {
    Mapper.CreateMap<Person, PersonDto>();
    var persons = _personRepository.GetPersonsAsQueryable();
    var personsDTOs = persons.Project().To<PersonDto>();  // magic happens here...

    return options.ApplyTo(personsDTOs);
}
publicIQueryable获取(ODataQueryOptions选项){
CreateMap();
var persons=_personRepository.getpersonasqueryable();
var personsDTOs=persons.Project().To();//这里发生了奇迹。。。
返回选项。ApplyTo(personsDTOs);
}
关于急切加载导航属性…

@菲利德:我在评论中没有一个像样的回应,所以我把它加在了这里。有一篇关于如何做到这一点的帖子,但我今天得到了403分。希望这只是暂时的

基本上,您可以检查导航属性的Select和EXPLAND子句。如果存在,则告诉EF通过
IQueryable Include
扩展方法急切地加载

控制器

public IQueryable GetMyDtos(ODataQueryOptions选项)
{   
var angelyLoad=options.IsNavigationPropertyExpected(t=>t.MyNavProperty);
var queryable=\u myDtoService.GetMyDtos(急切地加载);
//_myDtoService将急切地加载,以防止选择N+1问题
//return(急切加载)?efResults.Include(t=>t.MyNavProperty):efResults;
返回可查询;
}
扩展方法

公共静态类ODataQueryOptions扩展
{
公共静态bool IsNavigationPropertyExpected(此ODataQueryOptions源、表达式键选择器)
{
如果(source==null){抛出新的ArgumentNullException(“source”);}
如果(keySelector==null){抛出新的ArgumentNullException(“keySelector”);}
var returnValue=false;
var propertyName=(keySelector.Body作为MemberExpression???((UnaryExpression)keySelector.Body)。操作数作为MemberExpression)。Member.Name;
var expandProperties=source.SelectExpand==null | | string.IsNullOrWhiteSpace(source.SelectExpand.RawExpand)?new List().ToArray():source.SelectExpand.RawExpand.Split(',');
var selectProperties=source.SelectExpand==null | | string.isnull或空白(source.SelectExpand.RawSelect)?新建列表().ToArray():source.SelectExpand.RawSelect.Split(',');
returnValue=returnValue^expandProperties.Contains(propertyName);
returnValue=returnValue^selectProperties.Contains(propertyName);
返回值;
}
}
使用自动制表器

首先,定义映射

// Old AutoMapper API
// Mapper.CreateMap<Person, PersonDto>();

// Current AutoMapper API
Mapper.Initialize(cfg => 
   cfg.CreateMap<Person, PersonDto>()
);
//旧的自动映射API
//CreateMap();
//当前自动映射API
Mapper.Initialize(cfg=>
cfg.CreateMap()
);
然后,您可以使用如下内容:

[EnableQuery]
public IQueryable<PersonDto> Get() {
    // Old AutoMapper API
    // return this.dbContext.Persons.Project().To<PersonDto>();

    // New AutoMapper API
    return this.dbContext.Persons.ProjectTo<PersonDto>();
}
[启用查询]
公共IQueryable Get(){
//旧自动映射API
//将此.dbContext.Persons.Project()返回到();
//新自动映射API
返回此.dbContext.Persons.ProjectTo();
}

编辑2019年4月:更新以反映当前AutoMapper API。

我更新了一个似乎有效的示例,但我确信一定有更好的解决方案。天哪,我不能给你足够的放弃投票!谢谢你帮我找到那个!对于其他人,您可以在页面下方大约一半的MS文档中找到此示例。您使用
ODataQueryOptions
而不是
[Q
// Old AutoMapper API
// Mapper.CreateMap<Person, PersonDto>();

// Current AutoMapper API
Mapper.Initialize(cfg => 
   cfg.CreateMap<Person, PersonDto>()
);
[EnableQuery]
public IQueryable<PersonDto> Get() {
    // Old AutoMapper API
    // return this.dbContext.Persons.Project().To<PersonDto>();

    // New AutoMapper API
    return this.dbContext.Persons.ProjectTo<PersonDto>();
}