2014-10-18 44 views
4

如何限制web api &实体框架返回的列? 因为我仍然是一个新手,我希望尽可能多的信息成为可能;)如何限制web api返回的列?

我的控制器:

  //GET: api/Creditors 
    public IQueryable<Creditor> GetCreditors() 
    { 
     return db.Creditors; 
    } 

我的班级:

using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.Linq; 
using System.Web; 

namespace PurchaseOrders.Models 
{ 
public class Creditor 
{ 
    [Key] 
    public int CreditorID { get; set; } 

    [MaxLength(10, ErrorMessage = "Maximum of 10 characters")] 
    public string CRKEY { get; set; } 

    [Display(Name = "Business Name")] 
    [MaxLength(40, ErrorMessage = "Maximum of 40 characters")] 
    public string BusinessName { get; set; } 

    [MaxLength(40, ErrorMessage = "Maximum of 40 characters")] 
    public string Address { get; set; } 

    [MaxLength(40, ErrorMessage = "Maximum of 40 characters")] 
    public string City { get; set; } 

    [MaxLength(4, ErrorMessage = "Maximum of 4 characters")] 
    public string State { get; set; } 

    [MaxLength(4, ErrorMessage = "Maximum of 4 characters")] 
    public string Postcode { get; set; } 

    [MaxLength(15, ErrorMessage = "Maximum of 15 characters")] 
    public string Phone { get; set; } 

    [MaxLength(15, ErrorMessage = "Maximum of 15 characters")] 
    public string Fax { get; set; } 

    [MaxLength(60, ErrorMessage = "Maximum of 60 characters")] 
    public string Email { get; set; } 

    [MaxLength(60, ErrorMessage = "Maximum of 60 characters")] 
    public string Website { get; set; } 

    [MaxLength(30, ErrorMessage = "Maximum of 30 characters")] 
    public string ContactName { get; set; } 

    [MaxLength(15, ErrorMessage = "Maximum of 15 characters")] 
    public string ABN { get; set; } 

    [Display(Name = "Registered for GST")] 
    public bool RegisteredForGST { get; set; } 

} 

} 

这个当前返回:

[{"CreditorID":1,"CRKEY":"test1","BusinessName":"test1","Address":"7 Smith Street","City":"Melbourne","State":"VIC","Postcode":"3000","Phone":null,"Fax":null,"Email":null,"Website":null,"ContactName":null,"ABN":"null","RegisteredForGST":true},{"CreditorID":2,"CRKEY":"test2","BusinessName":"test2","Address":"10 Smith Street","City":"SYDNEY","State":"NSW","Postcode":"2000","Phone":null,"Fax":null,"Email":null,"Website":null,"ContactName":null,"ABN":"null","RegisteredForGST":true}] 

这是我想要的结果(只有“CreditorID”&“BUSINESSNAME”):

[{"CreditorID":1,"BusinessName":"test1"},{"CreditorID":2,"BusinessName":"test2"}] 

回答

1

在你的问题你”重新显示查询的json输出,所以我假设你正在通过Javascript发出GET请求。当您使用IQueryable作为API方法的返回值类型时,您应该能够利用WebApi提供的OData支持,以便您可以发出OData查询以仅选择所需的列。有关OData支持的更多详细信息,请参见this article

所以,首先,JavaScript端,假设jQuery的为便于回答的:

$.get('api/Creditors?$select=CreditorId,BusinessName', onSuccess) 

你想在一个逗号指定的列名在$select参数分隔的列表。 (该onSuccess是一个回调函数,你将定义哪些将要传递从API回来的数据。请参阅jQuery documentation了解更多详情。)

在服务器端,你可能需要从ODataController派生控制器代替的ApiController,您需要将[Queryable][EnableQuery]属性添加到GetCreditors()方法,具体取决于您使用的WebApi的版本。

如果您发现需要继承ODataController才能完成此工作,那就是配置OData端点,您还需要添加一点配置。为此,您需要类似于以下代码:

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     ODataModelBuilder builder = new ODataConventionModelBuilder(); 
     builder.EntitySet<Creditor>("Creditors"); 
     config.MapODataServiceRoute(
      routeName: "ODataRoute", 
      routePrefix: null, // or "api" ? 
      model: builder.GetEdmModel()); 
    } 
} 

您的网络启动代码中的某处(例如,Application_Start),就需要调用这个如下:

GlobalConfiguration.Configure(WebApiConfig.Register); 

取决于你如何设置你的项目了,有些后者的配置可能不是必要的,因为它会已经完成,但我认为我会提到它是很好的措施。有关详细信息,请参阅this page

+0

我一直在玩odata&看起来不错..它和webapi一样快吗?你知道它是否会在vnext中得到支持吗? – MWD 2014-10-21 15:06:06

+0

我不确定,但我期望。团队在此页面发表的评论(http://blogs.msdn.com/b/webdev/archive/2014/09/11/announcing-the-release-of-web-api-odata-5-3.aspx )表示当vNext处于“稳定”状态时,他们会查看“如何启用它”。那是在9月11日,所以事情可能会继续。它正在积极发展,所以我会想象它们将会移植。至于速度,我还没有看到任何速度问题。事实上,事实上正好相反,因为我已经设法对数据库进行更有针对性的查询了。 – 2014-10-21 16:00:19

+0

感谢Josh ..我在玩了一天的odata后觉得很印象深刻,并且认为我会尽我所能开始使用它;) – MWD 2014-10-21 20:14:12

1

这可以通过使用投影来完成,这里使用匿名类型示例:

db.Creditors 
    .Select(x => new { 
     x.CreditorID, 
     x.BusinessName, 
    }) 
    .ToArray() 

这将导致查询数据库,将只得到两个字段你需要的包裹在匿名课上。您可以直接从您的WebAPI控制器以JSON结果返回它。

如果你需要传递的结果(这是SomeAnonymousClassICanNotReference[]型)层之间,您可以使用dymanic关键字(实际上不是一个很好的选择),或者使用自定义类像Select(x => new MyClass { Id = x.CreditorID ...

+0

我仍然是一个新手&将需要看看你的回答更多..谢谢你的帮助:) – MWD 2014-10-21 15:12:08

+0

你能解释更多吗?我宁愿不使用odata。你的方法看起来像它应该工作,但它不适合我。 – 2015-08-14 22:27:11

+0

@ConnieDeCinko你有更具体的问题吗?你有什么尝试,什么不适合你,你有哪些问题? – Lanorkin 2015-08-17 11:57:04

1

在没有OData的情况下,有几种不同的方法可以处理这种需求。我倾向于使用投影查询(正如Lanorkin在他的回答中提到的)。这里有些例子。

1.返回一个动态类型从您的WebAPI控制器:

这是最快和最简单的方法。有人会认为动态返回类型是sl,不驯的,但他们完成了工作。

[HttpGet] 
public dynamic GetCreditors() { 
    return db.Creditors 
     .Select(x => new { 
     x.CreditorID, 
     x.BusinessName, 
    }).ToArray() 
} 

2.使用显式的返回类型在你的控制器:

除的WebAPI,这种方法适用于WCF不允许动态返回类型。如果您的标准做法是使用静态返回类型,这是一个“更好”的方法。

您的返回类型创建一个类:

public class CreditorResult { 
    public int CreditorID { get; set; } 
    public string BusinessName { get; set; } 
} 

那么你的API方法是这样的:

[HttpGet] 
public CreditorResult[] GetCreditors() { 
    return db.Creditors 
     .Select(x => new CreditorResult() { 
     x.CreditorID, 
     x.BusinessName, 
    }).ToArray() 
} 

3.使用模型属性来控制输出领域:

当前版本的WebAPI使用JSON.NET作为其序列化器,并且可以设置旧版本以使用它。您可以在模型上指定数据属性来告诉JSON.NET要包含或忽略哪些属性。

如果您使用实体框架的代码优先方法,那么您可以直接将属性添加到您的类。如果您使用数据库优先方法(代码生成),那么将您的属性放入Metadata类是最安全的。 http://www.ozkary.com/2015/01/add-data-annotations-to-entity.html

如果您只想包括几个字段,则应该将[DataContract]添加到类中,并将[DataMember]添加到属性中。输出中只包含[DataMember]的属性。例如,下面将只返回CreditorID和BUSINESSNAME:

[DataContract] 
public class Creditor 
{ 
    [DataMember] 
    [Key] 
    public int CreditorID { get; set; } 

    [DataMember] 
    [Display(Name = "Business Name")] 
    [MaxLength(40, ErrorMessage = "Maximum of 40 characters")] 
    public string BusinessName { get; set; } 
... 

如果你想包括你的领域,而忽略了几下,更容易的方法是添加[JsonIgnore]到要隐藏的属性。

public class Creditor 
{ 
    [Key] 
    public int CreditorID { get; set; } 

    [JsonIgnore] 
    [MaxLength(10, ErrorMessage = "Maximum of 10 characters")] 
    public string CRKEY { get; set; } 

    [Display(Name = "Business Name")] 
    [MaxLength(40, ErrorMessage = "Maximum of 40 characters")] 
    public string BusinessName { get; set; } 
... 

有很多其他的方式来微调输出。查看http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size了解更多详情。