2015-08-14 30 views
3

首先,這是不完全的幾十個其他職位的重複,我已經嘗試了所有的人,沒有他們的工作。只返回選定字段導致

我有一個包含比我的網頁API消費者需要更多的值的模型。

public class Publication 
{ 
    [Key] 
    public int PublicationID { get; set; } 
    public string PublicationTitle { get; set; } 
    public string Frequency { get; set; } 
    public DateTime NextIssueDate { get; set; } 
    public DateTime SpaceDeadline { get; set; } 
    public DateTime MaterialsDeadline { get; set; } 
    public DateTime CreatedDt { get; set; } 
    public string CreatedBy { get; set; } 
    public DateTime UpdatedDt { get; set; } 
    public string UpdatedBy { get; set; } 
} 

我只想說一些在API中傳遞的字段。我試過這段代碼,但沒有在Json結果中說出UpdateBy,而是用空值返回它。我該如何擺脫?我已經嘗試了幾十個版本,但它們要麼編譯失敗,要麼無法返回結果。

public IQueryable<Publication> GetPublications() 
    { 
     return db.Publications 
      .ToList() 
      .Select(p => new Publication { 
       PublicationID = p.PublicationID, 
       PublicationTitle = p.PublicationTitle, 
       Frequency = p.Frequency, 
       NextIssueDate = p.NextIssueDate 
      }) 
      .AsQueryable(); 
    } 

回答

6

這是因爲你返回Publication對象的集合,所以你會得到包含在該類的每個屬性,不管你填充與否。如果你想返回屬性的一個子集,然後創建一個只有你想返回的屬性的類,並在你的查詢中創建該類的一個實例。

public IQueryable<WhatIReallyWantToReturn> GetPublications() 
{ 
    return db.Publications 
     .ToList() 
     .Select(p => new WhatIReallyWantToReturn { 
      PublicationID = p.PublicationID, 
      PublicationTitle = p.PublicationTitle, 
      Frequency = p.Frequency, 
      NextIssueDate = p.NextIssueDate 
     }) 
     .AsQueryable(); 
} 

private class WhatIReallyWantToReturn 
{ 
    public int PublicationID { get; set; } 
    public string PublicationTitle { get; set; } 
    public string Frequency { get; set; } 
    public DateTime NextIssueDate { get; set; } 
} 
+0

是啊,這就是我需要做的,創建一個視圖模型。 –

+1

將查詢轉換爲可枚舉(通過ToList())然後返回可查詢沒有意義。省略.ToList()和.AsQueryable(),你有你的結果映射到新類直接從數據庫 –

1

克雷格W.說,你可以使用視圖模型,也可以使用匿名類型 (通知視圖模型是更好的辦法,因爲你可以使用一些實用工具,比如automapper自動映射你的財產)

+0

與匿名類型的唯一問題是,則該方法不能返回IQueryable的'',那就得是'動態'。這將工作,但它使單元測試一個真正的PITA。 –

5

別t序列化您的DAO。創建一個完整的合約,然後選擇性地序列化它。爲了爲不同的案例創建不同的合約,你可以使用Json.Net來簡化它;你可以只創建一個自定義的合同解析器和使用它作爲SerializeObject(的參數),像這樣

static void Main(string[] args) 
{ 
    var person = new TestContract {FirstName = "John", LastName = "Doe", Age = 36}; 

    var firstNameContract = new SelectiveSerializer("firstname"); 
    var allPropertiesContract = new SelectiveSerializer("firstname, lastname, age"); 

    var allJson = JsonConvert.SerializeObject(
     person, 
     Formatting.Indented, 
     new JsonSerializerSettings {ContractResolver = allPropertiesContract}); 

    var firstNameJson = JsonConvert.SerializeObject(
     person, 
     Formatting.Indented, 
     new JsonSerializerSettings {ContractResolver = firstNameContract}); 

    Console.WriteLine(allJson); 
    // { 
    // "FirstName": "John", 
    // "LastName": "Doe", 
    // "Age": 36 
    // } 


    Console.WriteLine(firstNameJson); 
    // { 
    // "FirstName": "John",  
    // }   
} 

public class SelectiveSerializer : DefaultContractResolver 
{ 
    private readonly string[] _fields; 

    public SelectiveSerializer(string fields) 
    { 
     var fieldColl = fields.Split(','); 
     _fields = fieldColl 
      .Select(f => f.ToLower().Trim()) 
      .ToArray(); 
    } 

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     var property = base.CreateProperty(member, memberSerialization); 
     property.ShouldSerialize = o => _fields.Contains(member.Name.ToLower()); 

     return property; 
    } 
} 

public class TestContract 
{ 
    public string FirstName { get; set; } 

    public string LastName { get; set; } 

    public int Age { get; set; } 
} 

沒有太多的精力,你也許可以將它變成您的默認介質類型格式(在管道中),以尋找一個請求中的參數稱爲「字段」或其他內容,然後使用自定義合約解析器(如果存在),然後它將是無縫的默認行爲,以限制字段(如果指定),或者如果未指定則序列化整個對象。

在學術方面,這裏是理由: 對數據的任何修改都被認爲是「查看問題」,這意味着在API中,它應該由查詢參數控制並接受標題。在這種情況下,數據的「表示」是application/json,並且您選擇「過濾」返回的字段。所有這些都可以(也應該是,imo)在序列化過程中處理。因此,在這種情況下,您的「模型」將始終是完整模型與模型的某個子集。本例中的完整模型包含名字,姓氏和年齡。實際上,這可能是數百個屬性。如果你想讓客戶端選擇完整模型的一個子集,這就是你如何通過選擇性序列化來完成的。

你可以在圖形API的類似行爲。還有,對於大型模型默認的是,你得到一個空的對象,如果你不指定領域,強制客戶端是非常具體的什麼,它要求,這是偉大的,當有效載荷大小事務(如移動應用)。而且,沒有什麼能夠阻止創建像'name'這樣的字段預設,這可能意味着包含所有屬性的'firstname,lastname'或'all'。

我從來沒有有數百個數據對象都有助於一些特設的要求是在某些情況下,需要更多的數據,而有些則需要較少的20個不同的上下文中使用的數據集的粉絲。國際海事組織(IMO)如果你必須經歷同樣的過程來獲取數據,無論它是否完成,你不應該浪費時間創建額外的對象來爲客戶端構建數據,這應該有助於實現這一目標。

+0

我喜歡你的'SelectiveSerializer'的想法;你知道有沒有這樣的圖書館?因爲進一步想要指定子字段的想法,說:'新的SelectiveSerializer(「firstname,mother.firstname,mother.age」);'...聽起來像一個很好的獨立項目本身 – sports

+1

顯然有FlexJSON,有一個include和exclude方法:'jsons = new JSONSerializer()。include(「name」,「age」,...)' – sports

+0

Json.Net開箱即用。你只需要實現他們的自定義串行器。這不是很難。我想我最後一次嘗試它,花了大約5分鐘,其中大部分只是搞清楚了3種方法中的每一種。你不必執行所有的操作。我給它列出了一個屬性名稱,只是比較了每個屬性的名稱,並將它們與不匹配的地方進行了短路。 – Sinaesthetic