使用 EF 和 WebAPI,如何返回 ViewModel 并支持 IQueryable/OData? [复制]
Posted
技术标签:
【中文标题】使用 EF 和 WebAPI,如何返回 ViewModel 并支持 IQueryable/OData? [复制]【英文标题】:Using EF and WebAPI, how can I return a ViewModel AND support IQueryable/OData? [duplicate] 【发布时间】:2013-02-07 03:25:03 【问题描述】:我有一个 ASP.NET WebAPI 项目。我最近为我的所有数据表创建了 EntityFramework 实体。但我不想将我的数据层和架构暴露给我的用户。如何将我的实体映射到 ViewModel(自动映射器?)并提供 IQueryable 返回类型,以便我的 API 支持 OData?
OData 支持查询组合和类似 SQL 的参数。我想我需要为查询组合部分提供某种双向翻译?这是否意味着自定义 LINQ 提供程序?我希望它比那更容易。
或者我应该放弃 IQueryable/OData 吗?
【问题讨论】:
【参考方案1】:我在这里找到了答案:Web API Queryable - how to apply AutoMapper?
您可以使用ODataQueryOptions<T>
类型的参数而不是使用[Queryable]
来针对您希望的任何类型或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);
the Microsoft page 解释了这种用法的细节。 (大约一半)
【讨论】:
我认为这种方法不再有效。除非参数更改为 ODataQueryOptionsodataQuery.ApplyTo(ConvertToDtos(uow.Person().GetAll()))
@EricFalsken 不会导致所有 Person 都被拉入内存以便 ConvertToDtos 可以对它们进行操作吗?
将ConvertToDtos
替换为Automapper.ConvertTo<PersonDto>()
或odataQuery.ApplyTo(db.Person().GetAll().To<PersonDto>())
,您将得到一个LINQ 查询,该查询只会转换必要的对象,而不会从数据库中取回所有内容,只要您使用 2-way 对象绑定语法。
@EricFalsken 但是如果您在执行查询之前将其转换为 DTO,您将如何处理关系?例如,我在尝试扩展时收到此错误:No NavigationLink factory was found for the navigation property 'Address' from entity type 'PersonDto' on entity set 'Persons'【参考方案2】:
我能够使用 ViewModel 类成功地对此进行测试。
public class InvoiceViewModel
public int InvoiceID get; set;
public string InvoiceNumber get; set;
在 Get 中,从您的实体中选择到您的视图模型中:
public override IQueryable<InvoiceViewModel> Get()
var ctx = new CreditPointEntities();
return ctx.Invoices.Select(i => new InvoiceViewModel
InvoiceID = i.InvoiceID,
InvoiceNumber = i.InvoiceNumber
).AsQueryable();
确保在 webapiconfig.cs 的模型构建器行中使用视图模型
modelBuilder.EntitySet<InvoiceViewModel>("Invoice");
有了这个,你可以使用像
这样的 urlhttp://website/odata/Invoice?$filter=InvoiceID eq 1
我通过 sql profiler 确认过滤器正在传递给 SQL。
【讨论】:
【参考方案3】:如果您使用 Automapper,您可以在其中使用投影。示例:
public class ProductsController : EntitySetController<Product, int>
private DbProductsContext _db = new DbProductsContext();
public override IQueryable<ProductDto> Get()
return _db.Products.Project().To<ProductDto>();
...
【讨论】:
真的不管用AutoMapper。这是因为 EntityFramework LINQ 提供程序(至少对于 DbContext,有人说 ObjectContext 不起作用)支持您可以在投影(选择)上查询结果并且它将识别并将其转换为查询原始数据源。 LINQ 如何允许将针对视图模型的查询转换为对原始数据源的查询?我不明白。我认为如果我们必须使用类型转换器(自定义方法)来映射类,它肯定行不通? 我知道 IQueryable 将允许 OData 查询针对已翻译的类执行,但如果不检索所有可能的Products
并将它们转换为 ProductDto
实例,我看不出这将如何工作.如何将 OData 查询转换为正确的 SQL?
Eric,在您的 Get 中的某个时刻,您必须提供从 DTO/ViewModel 到 EntityFramework 类的一些翻译,无论是通过直接映射(如我的示例中),还是通过自动映射器或类似的东西. OData 库可以使用它来确定如何将过滤器传递给实体框架,以便将您的 Select 转换为正确的 SQL。以上是关于使用 EF 和 WebAPI,如何返回 ViewModel 并支持 IQueryable/OData? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
使用 Asp.Net WebApi + EF + Odata 深度插入数据
AngularJs + WebApi + EF + SqlServer 一步一步搭建项目