2017-08-24 121 views
1

一個有點人爲的但卻很重要的例子。JSON補丁和「聚合」DTO

假設UserDetails是由RESTful Web服務使用的聚合DTO(不清楚正確的術語,請教育我,但基本上是來自不同商店/服務的收集信息的模型)。它不一定具有與其收集在一起的對象相同的屬性名稱。

public class UserDetails 
{ 
    public int UserId { get;set; } 
    public string GivenName { get; set; } 
    public string Surname { get; set; } 
    public int? UserGroupId { get;set; } // FK in a different database 
} 

讓我們的店堅持以下型號:

public class User 
{ 
    public int Id { get; set; } 
    public string GivenName { get; set; } 
    public string Surname { get; set; } 
} 


public class UserGroup 
{ 
    public int UserId { get; set; } 
    public int GroupId { get; set; } 
} 

讓的UserDetails對象正是如此填充:

User user = _userService.GetUser(userId) ?? throw new Exception(); 
UserGroup userGroup = _userGroupService.GetUserGroup(user.Id); 

UserDetails userDetails = new UserDetails { 
    UserId = user.Id, 
    GivenName = user.GivenName, 
    Surname = user.Surname, 
    UserGroupId = userGroup?.GroupId 
}; 

也就是說,設置FirstNameSurname應該委託給UserService,和UserGroupIdGroupService

UserDetails對象用於GET和PUT,這裏的邏輯非常簡單,但是此對象的JSON Patch文檔是針對PATCH請求發送的。這顯然要複雜得多。

我們該如何去改變用戶的組?最好的(「最好」的使用非常鬆散),我想出了是這樣的:

int userId; 
JsonPatchDocument<UserDetails> patch; 

// This likely works fine, because the properties in `UserDetails` 
// are named the same as those in `User` 
IEnumerable<string> userPaths = new List<string> {"/givenName", "/surname"}; 
if (patch.Operations.Any(x => userPaths.Contains(x.path))) { 
    User user = _userService.GetUserByUserId(userId); 
    patch.ApplyTo(user); 
    _userService.SetUser(userId, user); 
} 

// Do specialised stuff for UserGroup 
// Can't do ApplyTo() because `UserDetails.UserGroupId` is not named the same as `UserGroup.GroupId` 
IEnumerable<Operation<UserDetails>> groupOps = patch.Operations.Where(x => x.path == "/userGroupId"); 
foreach (Operation<UserDetails> op in groupOps) 
{ 
    switch (op.OperationType) 
    { 
     case OperationType.Add: 
     case OperationType.Replace: 
      _groupService.SetOrUpdateUserGroup(userId, (int?)(op.value)); 
      break; 

     case OperationType.Remove: 
      _groupService.RemoveUserGroup(userId); 
      break; 
    } 
} 

,這是相當可怕的華麗地。這是很多樣板,並依靠一個魔術字符串。

,而無需請求Microsoft.AspNetCore.JsonPatch API的變化,像

JsonPatchDocument<UserDetails> tmpPatch = new JsonPatchDocument<UserDetails>(); 
tmpPatch.Add(x => x.GivenName, String.Empty); 
tmpPatch.Add(x => x.Surname, String.Empty); 
IEnumerable<string> userPaths = tmpPatch.Operations.Select(x => x.path); 

東西至少會幹掉魔術字符串,但,IMO,這只是感覺錯了!

JsonPatch在這方面似乎非常有限,似乎更適合於DAO(實體)和DTO(模型)之間存在1:1映射的系統。

任何人有任何好主意?不能很難打敗我想出來的肚子!

回答

0

Json Merge Patch - RFC7396會更適合這個。