ASP.NET MVC 和 EF 多连接缩放

ASP.NET MVC & EF multiple joins scaling

我正在使用 ASP.NET MVC 和 Entity Framework 从单个 API 连接到多个数据库。我目前正在重构一些遗留代码以减轻服务器负载(我们预计在不久的将来会有很大的提升)。

有几个控制器有类似的问题,每次为 return 生成特定对象时都会消耗大量 CPU 电量。目前使用的方法是为每个table创建一个对象,然后从检索到的table中构造一个对象。

像这样:

public IHttpActionResult Get(string code) 
{
    using (DataEntities entities = new DataEntities()) 
    {
        var table1 = entities.Table1.FirstOrDefault(t1 => t1.ItemCode == code);

        if (table1 == null) 
        {
            return NotFound();
        }

        var table2 = entities.Table2.FirstOrDefault(t2 => t2.ItemId == table1.ItemId);
        var table3 = entities.Table3.FirstOrDefault(t3 => t3.ItemId == table1.ItemId);
        return Ok(new TableValues() 
                      {
                          ItemCode = code,
                          Table1Value = table1.Value;
                          Table2Value = table2.Value;
                          Table3Value = table3.Value;
                      });
    }
}

class TableValues 
{
    public string ItemCode;
    public int Table1Value;
    public int Table2Value;
    public int Table3Value;
}

我最近做的优化是从查询中删除额外的数据,并在缺少数据时设置默认值,而只是 select 需要什么,在这个例子中 Table1 有 200 多个字段和我只需要几个,所以这将时间从大约 180 毫秒减少到 10 毫秒:

public IHTTPActionResult Get(string code) 
{
    using (DataEntities entities = new DataEntities()) 
    {
        var table1 = entities.Table1 
                             .FirstOrDefault(t1 => t1.ItemCode == code)
                             .Select(t1 => new Table1Short()  
                                               {
                                                   ItemCode = t1.ItemCode,
                                                   Value1 = t1.Value1,
                                                   Value2 = t1.Value2,
                                                   Value3 = t1.Value3
                                               });
        if (table1 == null) 
        {
            return NotFound("Not found in database");
        }

        return Ok(table1);
    }
}

class Table1Short 
{
    public string ItemCode = string.Empty;
    public int Value1 = 0;
    public int Value2 = 0;
    public int Value3 = 0;
}

有没有什么方法可以创建具有多个 table 的 IQueryable,然后应用 .Select 来使用各种连接的 table 构造对象?

最终结果将如下所示:

public IHttpActionResult Get(string code) 
{
    using (DataEntities entities = new DataEntities())  
    {
        // THIS LINE WONT WORK AS IS
        var tableValuesQuery = entities.Table1
                                       .Join(entities.Table2 as t2)
                                       .Join(entities.Table3 as t3);

        table1 = tableValuesQuery.FirstOrDefault((t1, t2, t3) => t1.ItemCode == code)
                                 .Select((t1, t2, t3) => new TableValues() 
                                                         {
                                                             ItemCode = t1.ItemCode
                                                             Value1 = t1.Value,
                                                             Value2 = t2.Value,
                                                             Value3 = t3.Value
                                                         });
        // ADDITIONAL CODE TO JOIN TABLES HERE AS "t2" and "t3"
        if (table1 == null) 
        {
            return NotFound("Not found in database");
        }

        return Ok(table1);
    }
}

class TableValues 
{
    public int ItemId = string.Empty;
    public int Table1Value = 0;
    public int Table2Value = 0;
    public int Table3Value = 0;
}

这样做会稍微提高速度并防止 API 用户端因丢失数据(不可空数据类型中的空值)而出错。我检查了文档,发现只有 2 个 table 被加入的例子,我似乎无法与 3.

一起正常工作

最后一点:我只想创建一个 SQL 视图并将其导入到 EF 中,但遗憾的是这不是一个选项,因为某些数据库的修改是使用它们的程序所独有的。

感谢“Kirk Wolf”的回答。通过在我的数据模型中添加关联,我能够创建与问题中的第二段代码非常相似的结果。在(较小的)查询和 运行 一些基准测试中执行此操作后,性能似乎从平均 20 毫秒变为平均 5 毫秒。一个非常受欢迎的提升应该转化为更大控制器的更多时间节省。 步骤:

  1. 向数据模型添加关联

  2. 重新编译

  3. 访问对象如下

    public IHttpResult Get(string code) {
      var result = entities.Table1.Where(t1 => t1.ItemCode == code)
        .Select(t1 => new TableValues() {
          ItemCode = t1.ItemCode,
          Value1 = t1.Value,
          Value2 = t1.Table2.Value
          Value3 = t1.Table3.Value
        })
        .FirstOrDefault();
    
      if (result == null) {
        return NotFound();
      }
      return Ok(result);
    }
    

作为最后的说明,这里是我测试的一些细节:

  • 控制器连接了来自 6 个表的数据并对其进行了最少的处理(仅 3 个字段)。

  • 表格共有 487 个字段。

  • returned字段一共22个,2个在controller中生成,1个在controller中修改。

  • 准备对象 return 的总时间从平均 20 毫秒减少到平均 5 毫秒。