将OData添加到Web API 2中,而不耦合客户端和服务器



我想添加OData语法来查询应用程序的数据。我不想完全实现ODataController,但有ApiController并实现一个支持OData查询的GET操作,如下所述:在ASP.NET Web API 2 中支持OData Query Options

我想要的示例:

public class LetterEntity
{
public int Id {get; set;}
public string Title {get; set;}
public string Content {get; set;}
public string Source {get; set;}
public DateTime SendingTime {get; set;} 
public string AnotherWierdString {get; set;
...
}
public class LetterDTO
{
public int Id {get; set;}
public string Title {get; set;}
public string LetterContent {get; set;}
public string Source {get; set;}
public DateTime SendingTime {get; set;} 
}
public class LetterInsideFolderDTO 
{
public string Title {get; set;}
public string Source {get; set;}
}

public class LettersController : ApiController
{           
// Is there a way to do something like the following?:  
[HttpGet]
[Route("api/letters")]
[EnableQuery]
public IQueryable<LetterInsideFolderDTO> Get(ODataQueryOptions<LetterDTO> query) 
{ 
IQueryable<Letter> letters = db.Letters;
var queryOnEntites = // Convert the query to work on the entities somehow? - This is where I need help!!
var afterQuery = query.ApplyTo(letters)
IQueryable<LetterInsideFolderDTO> dtos = afterQuery.ProjectTo<LetterInsideFolderDTO>(afterQuery)
return dtos;
}
}

因为现在我直接在客户端查询中使用实体模型,所以客户端和服务器之间存在很强的耦合。例如,如果我想查询并获取Content字段中所有带有"abc"的字母,我需要路由到以下位置:

api/letters/?$filter=contains(Content,'abc')

如果明天我决定将该属性从"Content"更改为"LetterContent",则所有客户端代码都将被破坏。

我怎样才能超越它?

我还没有尝试过。这和这可以帮助你通过使用路由器映射和控制器选择器将查询url映射到实际控制器,在那里你可以将LetterDto映射到LetterEntity

这将适用于实体框架(不确定是否适用于Nhibrenate,但可能会),并将执行真正的SQL查询,而不是内存过滤。

var queryOnEntites = db.Letters.Select(l=>new LetterDTO{Id =l.Id ... });
var afterQuery = query.ApplyTo(queryOnEntites);

但是,如果您想使某些属性成为API使用builder.EntitySet<T1>("TEndpoint").EntityType.Ignore(o => o.SomeProp);的私有属性,则不应将DTO与odata一起使用现在,如果你不想把整个LetterEntity发送到客户端,你有$select=Id,。。。选项。如果不设置config.MapODataServiceRoute( routeName: "ODataRoute", routePrefix: null, model: builder.GetEdmModel());您没有Odata端点,$metadata将不可用。我还没有测试过它,但通过这种方式,我认为客户端库(.net、java、js…)无法工作,您将不得不发出原始ajax请求来获取数据。

ODataQueryOptions<>并将其翻译为ODataQueryOptions<>

你不能这么做。ProjectTo(AutoMapper)的功能与.Select(l=>new LetterDTO{Id =l.Id ... });的功能相同,但您会遇到问题。这一切都取决于您的后端,因为IQueryable与IEnumerable不同。http://blog.ploeh.dk/2012/03/26/IQueryableTisTightCoupling/

这一切都取决于您的后端提供的LINQ级别(NHibrenate往往比EF更差,如果您使用Mongo、Elastic、Cassandra…谁知道当您使用AutoMapper时会出现什么问题)

如果明天我决定将该属性从"内容"更改为"LetterContent"所有客户端代码都将被破坏。

您可以在具有oData的实体集上设置Name属性。请记住,Odata是数据访问级别,而不是BL。您应该像更改数据库中的SQL列名一样对待它。

与其直接公开实体模型,不如创建与每个实体模型相对应的ViewModels。它们只不过是简单的类,具有相同或仅需要的属性,我们希望将这些属性暴露在外部世界。以这种方式实现后,实体模型属性可能会更改,但ViewModels可以保持不变。您还解决了不向最终客户公开实体的每个属性的安全问题。

实体模型和ViewModel之间的映射必须由您自己或由对象对象映射器(如AutoMapper)完成。

最新更新