0

我有 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}

但我也得到了表中未指定的字段:客户、companyToProducts、发票。Invoices 和 CompaniesToProducts 是我数据库中的表,我不知道客户指的是什么。我还应该提到这些表是通过外键连接的。 在此处输入图像描述

在此处输入图像描述

更新
错误: 在此处输入图像描述

4

1 回答 1

1

根据对上述问题的评论,听起来相关表都在尝试序列化,并且由于对象图中的循环引用,整个过程可能会失败。上面的评论特别暗示了一个解决方案:

我只想返回有关公司的数据,但控制器还返回其他字段,如客户、companyToProducts、发票

虽然直接从数据上下文返回很方便,但这增加了将 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 项目中并且这是您拥有的唯一项目,那么强烈希望返回这些模型。

在这种情况下,另一种选择可能是将您的 JSON 序列化设置为忽略循环引用

services.AddMvc()
          .AddJsonOptions(
                options => options.SerializerSettings.ReferenceLoopHandling
                    = Newtonsoft.Json.ReferenceLoopHandling.Ignore );

但请记住,这仍然会将您的 API 与数据库模型耦合起来。也许在这个项目中这没问题,但是如果您向数据库中添加了一个您不希望用户看到的列,那么它就会成为一个问题。与任何事情一样,您有选择。

于 2018-12-23T14:08:55.823 回答