ASP.NET WebApi OData对DTO的支持

我有Project实体和ProjectDTO。 我正在尝试创建一个WebAPI控制器方法,可以获取并返回ProjectDTO并使其支持OData。

问题是我正在使用可以使用Project实体而不是Project DTO查询数据库的ORM。 有没有办法可以根据ProjectDTO从OData应用过滤/排序/分页到Project实体查询?

public ODataQueryResult GetProjects(ODataQueryOptions query) { var context = new ORM_Context(); var projects = context.Projects; // IQueryable var projectDtos = query.ApplyTo(projectDTOs)); //  new ProjectDTO { Id = x.Id, Name = x.Name }); var projectsQueriedList = projectDtos.ToList(); var result = new ODataQueryResult(projectsQueriedList, totalCount); return result; } 

这样的东西(我还没试过编译)

 using(var dataContext = new ORM_Context()) { var projects = dataContext.Projects; // IQueryable //Create a set of ODataQueryOptions for the internal class ODataModelBuilder modelBuilder = new ODataConventionModelBuilder(); modelBuilder.EntitySet("Project"); var context = new ODataQueryContext( modelBuilder.GetEdmModel(), typeof(Project)); var newOptions = new ODataQueryOptions(context, Request); var t = new ODataValidationSettings() { MaxTop = 25 }; var s = new ODataQuerySettings() { PageSize = 25 }; newOptions.Validate(t); IEnumerable internalResults = (IEnumerable)newOptions.ApplyTo(projects, s); int skip = newOptions.Skip == null ? 0 : newOptions.Skip.Value; int take = newOptions.Top == null ? 25 : newOptions.Top.Value; var projectDTOs = internalResults.Skip(skip).Take(take).Select(x => new ProjectDTO { Id = x.Id, Name = x.Name }); var projectsQueriedList = projectDtos.ToList(); var result = new ODataQueryResult( projectsQueriedList, totalCount); return result; } 

我认为最简单的方法是使用AutoMapper。 所以,对你的DTO来说

  [DataContract(Name = "Products")] public class ProductDTO { [Key] [DataMember] public string MyProductMember1 { get; set; } [DataMember] public string MyProductMember2 { get; set; } ... } 

你应该在AutoMapper配置中写一些地方:

 Mapper.CreateMap(); 

以及为OData构建IEdmModel的某个地方:

 builder.EntitySet("Products"); 

并且控制器的代码看起来像

 public class ProductsController : ODataController { [EnableQuery] public IHttpActionResult Get() { var products = context.Products; // IQueryable return Ok(products.Project().To()); } } 

这样您就不需要直接公开ORM实体,并且可以使用OData进行过滤,分页,计数甚至扩展嵌套集合,对于EF,它将使用Product映射到的表转换为相应的SQL请求。 但要小心:对于更复杂的情况(例如,嵌套集合),可能会导致非最佳SQL请求。

试试这个:

  public object GetProjects(ODataQueryOptions query) { var context = new ORM_Context(); var projects = query.ApplyTo(context.Projects); var projectDTOs = projects.Select( x => new ProjectDTO { Id = x.Id, Name = x.Name }); return new { TotalCount = Request.GetInlineCount(), //before paging Results = projectDTOs.ToList() }; } 

显然,最重要的是将正确的类型传递给ODataQueryOptions <>然后它就可以很好地执行它的魔法。 这是因为它使用该特定类型来查询您的集合/ db上下文,因此它必须是实际存储在集合/上下文中的类型,而不是您要返回的内容。

显然,你的DTO应该与你的ORM对象非常相似(并且它们在你的代码片段中也是如此),否则从用户/客户的角度来看这不会很好。

我没有尝试编译上面的代码,因为我没有你的类和其他基础设施,但它应该足以传达这个想法。