.net core 2使用深层属性格式化API响应



我正在构建一个应用程序,该应用程序仅包含一个使用.net core 2.1的API。

我有一个家长班(爸爸(,只有一个孩子(孩子(。我正在寻找最有效的方法来格式化我的控制器的JSON响应;为那些将我的API集成到他们的应用程序的开发人员。

public class Dad
{
public long Id{get;set;}
public string Name{get;set;}
public Kid OnlyChild {get;set;}
}
public class Kid
{
public long Id{get;set;}
public string FirstName{get;set;}
public string LastName{get;set;}
public string Useless{get;set;}
}

目前我正在控制器中做这样的事情:

[HttpGet("{id}")]
public async Task<IActionResult> GetDad([FromRoute] long id)
{
dynamic DadResponse = _context.Dads
.Where(o => o.Id == id)
.AsNoTracking()
.Select(p => new
{
Dad = p.Name, 
Kid = string.Format("{0} {1}", p.Kid.FirstName, p.Kid.LastName)
}).FirstOrDefault();
return Ok(DadResponse);
}

这种方法的好处是:

  1. 生成的DadResponse对象具有我想要的格式API
  2. EF Core生成的MySQL查询结果为优化,只选择爸爸。名字,孩子。名字和孩子。姓氏

缺点是如果Kid为null,它将生成一个异常。

解决这一问题的最佳方法是什么;也许我在一起使用了一种错误的方法。我尝试在我的模型中使用JsonIgnore属性,但我的每个控制器可能需要返回稍微不同的属性(例如,GET/Kids将返回所有带Id的孩子,而GET/Dads可能只返回上述格式(。

更新:理想情况下,如果爸爸没有Kid,我希望Kid返回null值,但我不能这样做:

Kid = (Kid == null ? null : string.Format("{0} {1}", p.Kid.FirstName, p.Kid.LastName))

我尝试在选择后动态更新值,使用以下内容:

dynamic DadResponse = _context.Dads
.Where(o => o.Id == id)
.AsNoTracking()
.Select(p => new
{
Dad = p.Name, 
Kid = p.Kid
}).FirstOrDefault();

DadResponse.Kid = (DadResponse.Kid == null ? null : string.Format("{0} {1}", DadResponse.Kid.Firstname, DadResponse.Kid.Lastname);
return Ok(DadResponse);

但这又是一个例外。

您的查询是一个将被转换为SQL的EF查询。Null传播无法转换,这就是您出现该错误的原因。

您不需要来格式化EF查询中的字符串,但您可以加载所需的数据,并使用另一个LINQ to Objects查询将其映射到其最终形式。如果您只加载一个对象,则可以返回一个新的匿名类型:

例如:

var data = _context.Dads
.AsNoTracking()
.Where(o => o.Id == id)        
.Select(p => new {
Dad = p.Name, 
Kid = new {p.Kid?.FirstName, p.Kid?.LastName}
})
.FirstOrDefault();
var dadResponse = new {
data.Dad,
Kid= $"{data.Kid.FirstName} {data.Kid.LastName}"
};
return Ok(dadResponse);

如果根本不想返回Kid元素,可以简单地从结果中省略它:

if (data.Kid.FirstName==null && data.Kid.LastName==null)
{
return Ok(new {Dad=data.Dad});
}
else 
{
...
}

当然,有人可能会说,由于我们不关心Kid属性,我们可以将KidFirstName和KidLastName作为单独的属性返回,从而使代码更简单:

var data = _context.Dads
.AsNoTracking()
.Where(o => o.Id == id)        
.Select(p => new {
Dad = p.Name, 
KidFirstName = p.Kid?.FirstName
KidLastName =  p.Kid?.LastName
})
.FirstOrDefault();
if (data.KidFirstName==null && data.KidLastName==null)
{
return Ok(new {data.Dad});
}
else 
{
return Ok(new {data.Dad,Kid=$"{data.KidFirstName} {data.KidLastName}");
}

最新更新