我有asp.net Web API应用程序。我在数据库中有表Companies,其中有两个字段:id和description。最近,我更新了数据库并添加了一个名为CustomerID的新列。之后,当我尝试致电getCompanies
private readonly BackendContext _context;
public CompaniesController(BackendContext context)
{
_context = context;
}
// GET: api/Companies
[HttpGet]
public IEnumerable<Company> GetCompanies()
{
return _context.Companies;
}
我明白了
我认为控制者试图返回旧公司模型,但由于它现在不存在而无法实现,但是我不知道如何解决这个问题,尽管控制者应该返回更新后的模型。也许我应该以某种方式重建应用程序以使其使用更新的版本?
附加代码: 上下文
public class BackendContext : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext<IdentityUser>//DbContext
{
public BackendContext(DbContextOptions<BackendContext> options) : base(options) { }
public DbSet<Company> Companies { get; set; }
public DbSet<CompanyToProduct> CompanyToProducts { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Vendor> Vendors { get; set; }
public DbSet<VendorToProduct> VendorToProducts { get; set; }
public DbSet<Invoice> Invoices { get; set; }
public DbSet<InvoiceItem> InvoiceItems { get; set; }
}
型号
public class Company
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<CompanyToProduct> CompaniesToProducts { get; set; }
public virtual ICollection<Invoice> Invoices { get; set; }
}
更新 我在表中添加了一些值,并且得到了第一家公司的回复:
[{"id":1,"name":"Google","description":"free food","customerID":6,"customer":null,"companiesToProducts":null,"invoices":null}
但是我还得到了表中未指定的字段:customer,companiesToProducts,发票。发票和companyToProducts是我数据库中的表,我不知道客户指的是什么。我还应该提到这些表是通过外键连接的。
答案 0 :(得分:1)
基于对以上问题的评论,听起来相关表都在尝试序列化,并且整个过程可能由于对象图中的循环引用而失败。上面的评论特别提示了解决方案:
我只想返回有关公司的数据,但控制器还返回其他字段,例如客户,companiesToProducts,发票
虽然直接从数据上下文中返回很方便,但这具有将API与数据库(和与数据访问框架)耦合的附加副作用,这似乎是问题所在这里)。通常,在API设计中,明确定义该API的“形状”总是一个好主意。要返回的字段,等等。
将结果投影为明确定义的形状,并仅返回要返回的结果:
var result = _context.Companies
.Select(c => new
{
c.ID,
c.Name,
c.Description,
c.CustomerID
})
.ToList();
这专门定义了您要返回的内容,仅从支持数据中获取该信息,将其具体化为内存中列表,最后通过API返回。
但是,这有潜在的不利影响。因为现在我们还需要更改API方法的返回类型。那里有几个选项,例如返回通用响应对象或创建一个与您已经存在的模型非常接近的视图模型,并开始让人感到重复。
几乎所有东西都保持平衡。在任何一个方向上距离都太远,该方向开始成为问题。我个人经常走定义视图模型返回的路线:
public class CompanyViewModel
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CustomerID { get; set; }
}
并返回:
return _context.Companies
.Select(c => new CompanyViewModel
{
ID = c.ID,
Name = c.Name,
Description = c.Description,
CustomID = c.CustomerID
})
.ToList();
但是我通常这样做的原因是因为我通常在Web应用程序只是附加到公共共享业务域的一个应用程序的环境中工作,因此视图模型感觉不像代码重复。它们位于单独的项目中,其形状通常与支持数据的对象等不同。但是,如果您的域模型已经存在于Web项目中,并且这是您唯一的项目,则强烈希望返回这些模型。
另一种情况是universally set your JSON serialization to ignore circular references:
services.AddMvc()
.AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore );
但是请记住,这仍然会将您的API耦合到您的数据库模型。在这个项目中也许没关系,但是如果您向数据库中添加了不希望用户看到的列,则成为问题。像其他任何东西一样,您可以选择。