使用EF和WebAPI,如何返回ViewModel并支持IQueryable/OData?

Eri*_*ken 11 entity-framework iqueryable odata asp.net-web-api

我有一个ASP.NET WebAPI项目.我最近为我的所有数据表创建了EntityFramework实体.但我不想将我的数据层和架构公开给我的用户.如何将我的实体映射到ViewModel(automapper?)提供IQueryable返回类型,以便我的API支持OData?

OData支持查询组合和类似SQL的参数.我想我需要为查询组合部分提供某种双向翻译?这是否意味着自定义LINQ提供程序?我希望它比那更容易.

或者我应该放弃IQueryable/OData?

Eri*_*ken 10

我在这里找到了答案:Web API Queryable - 如何应用AutoMapper?

而不是使用[Queryable]您可以使用类型的参数ODataQueryOptions<T>来针对您希望的任何类型或LINQ查询应用OData操作.这是一个甚至不需要使用AutoMapper的好例子:

public virtual IQueryable<PersonDto> Get(ODataQueryOptions<Person> odataQuery){
    odataQuery.Validate(new ODataValidationSettings(){
        AllowedFunctions = AllowedFunctions.AllMathFunctions
    });
    var people = odataQuery.ApplyTo(uow.Person().GetAll());
    return ConvertToDtos(people);
}
Run Code Online (Sandbox Code Playgroud)

这是Microsoft页面,解释了这种用法的细节.(大约一半)

  • @EricFalsken不会导致所有人被拉入内存,所以ConvertToDtos可以对它们进行操作吗? (4认同)
  • 我认为这种方法不再适用.除非将参数更改为ODataQueryOptions <PersonDto>,否则不会调用该方法.如果将参数更改为该参数,则会调用该方法,但odataQuery.ApplyTo()会抛出异常,表示该查询适用于PersonDto类型,而不是Person. (3认同)
  • @EricFalsken 但如果在执行查询之前将其转换为 DTO,您将如何处理关系?例如,我在尝试扩展时收到此错误:未找到实体集“Persons”上实体类型“PersonDto”中导航属性“Address”的 NavigationLink 工厂 (3认同)

Gar*_*rez 6

我能够使用ViewModel类成功测试它.

public class InvoiceViewModel
{
    public int InvoiceID { get; set; }
    public string InvoiceNumber { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在Get中,从您的实体中选择您的viewmodel:

public override IQueryable<InvoiceViewModel> Get()
    {
        var ctx = new CreditPointEntities();
        return ctx.Invoices.Select(i => new InvoiceViewModel
            {
                InvoiceID = i.InvoiceID,
                InvoiceNumber = i.InvoiceNumber
            }).AsQueryable();
    }
Run Code Online (Sandbox Code Playgroud)

确保在webapiconfig.cs中的modelbuilder行中使用viewmodel

modelBuilder.EntitySet<InvoiceViewModel>("Invoice");
Run Code Online (Sandbox Code Playgroud)

有了这个,你可以使用像这样的网址

http://website/odata/Invoice?$filter=InvoiceID eq 1

我通过sql profiler确认过滤器正在传递给SQL.