【问题标题】:Is there a way to add a where clause on a Select within a Select - I need to reduce the amount of JSON returned有没有办法在 Select 中的 Select 上添加 where 子句 - 我需要减少返回的 JSON 数量
【发布时间】:2019-05-13 07:04:32
【问题描述】:

这个问题是关于尝试通过在我的 Selects 上添加 where 或完全重写查询来使我的代码返回更少量的结果以提高解决方案的效率。

注意这是使用 C# .NET Framework 4.7.2。 (我们还没有迁移到 Core)。

我有以下实体:PERSON、PERSON_TYPE、COINS 和 FINANCIAL_YEAR。

  • 一个 PERSON 有一个 PERSON_TYPE(一对多),
  • 一个人有很多硬币(多对多的左侧),
  • 硬币有许多 FINANCIAL_YEARS(多对多的右侧)

(一个人也可以有一个或多个办公室,我为完整性保留了这些办公室)。

例如一个人可以有一套硬币 2016 年 10 枚,2017 年 29 枚,2018 年 37 枚等

我得到了返回的结果,但在尝试过滤特定年份的结果时,我得到了所有硬币的返回,但只有“金融年”我想要延迟加载。

我试过下面的代码查询

    var persons = appCoreDBContext.PersonRepository.GetAll()
                  .Where(p => p.Active.Equals(true))
                  .Select(pl => new
                  {
                     pl,
                     PersonLocs = pl.PersonLocations.Where(ed => ed.EndDate != null)
                     .Select(o => new
                     {
                         o,
                         office = o.Office
                     }),
                     PersonType = pl.PersonType,
                     PersonCoins = pl.PersonCoins
                     .Select(yr => new
                     {
                         yr,
                         finYear = yr.FinancialYear
                     })
                     .Where(ee => ee.finYear.StartDate.Year == DateTime.Now.Year)
                  })
                  .AsEnumerable()
                  .Select(x => x.pl);

所以这会以 JSON 格式返回以下结果

[
  {
    "id": 1,
    "lastModifiedDate": "2019-05-09T11:47:10.193",
    "active": true,
    "firstName": "Fred",
    "lastName": "Flintstone",
    "title": "Mr",
    "email": "fred.flintstone@slaterockandgravel.com",    
    "personTypeId": 2,
    "personType": {
      "id": 2,
      "name": "Blue-Collar"
    },
    "personCoins": [
      {
        "id": 118,
        "lastModifiedDate": "2019-05-12T23:01:33.1566667",
        "active": true,
        "fullYearValue": 102.0,        
        "personId": 1,        
        "financialYearId": 19,
        "financialYear": {
          "id": 19,
          "lastModifiedDate": "2019-04-30T15:33:20.05",
          "active": true,
          "startDate": "2019-05-01T00:00:01",
          "endDate": "2020-04-30T00:00:00",
          "label": "FY 2019/2020"
        }
      },
      {
        "id": 1,
        "lastModifiedDate": "2019-04-29T07:49:41.367",
        "active": true,
        "fullYearValue": 85.0,        
        "personId": 1,        
        "financialYearId": 3,
        "financialYear": null
      },
      {
        "id": 2,
        "lastModifiedDate": "2019-04-29T07:50:14.747",
        "active": true,
        "fullYearValue": 65.0,        
        "personId": 1,        
        "financialYearId": 2,
        "financialYear": null
      },
      {
        "id": 3,
        "lastModifiedDate": "2019-04-29T07:50:41.307",
        "active": true,
        "fullYearValue": 45.0,        
        "personId": 1,        
        "financialYearId": 1,
        "financialYear": null
      },
      {
        "id": 109,
        "lastModifiedDate": "2019-05-09T18:02:34.52",
        "active": true,
        "fullYearValue": 100.0,        
        "personId": 1,        
        "financialYearId": 20,
        "financialYear": null
      },
      {
        "id": 112,
        "lastModifiedDate": "2019-05-09T19:00:09.787",
        "active": true,
        "fullYearValue": 101.0,        
        "personId": 1,       
        "financialYearId": 21,
        "financialYear": null
      },
      {
        "id": 115,
        "lastModifiedDate": "2019-05-09T19:04:15.853",
        "active": true,
        "fullYearValue": 101.0,        
        "personId": 1,       
        "financialYearId": 22,
        "financialYear": null
      }
    ],
    "personLocations": [
      {
        "id": 1,
        "lastModifiedDate": "2019-04-25T10:19:07.193",
        "active": true,
        "startDate": "2018-10-29T09:00:00",
        "endDate": null,
        "office": {
          "id": 2,
          "lastModifiedDate": "2019-04-25T10:16:37.9533333",
          "active": true,
          "name": "Bedrock",
          "address1": "The Quarry",
          "address2": "Bedrock",
          "address3": "Prehistorica",
          "zipcode": "YabbaDabbaDoo",
          "openingDate": "1992-06-01T09:00:00",
          "closingDate": null,
          "officialCurrencyId": 1,
          "officialCurrency": null,
          "countryId": 1,
          "country": null
        }
      }
    ]
  }
]

正如您在上面看到的,我确实获得了我想要 2019 年的财政年度信息,但我还获得了我不想要的其他财政年度的所有其他 COIN 数据,这使得响应更大。

为了让这个结果集更高效,我想要的是我返回的结果看起来像

    [
  {
    "id": 1,
    "lastModifiedDate": "2019-05-09T11:47:10.193",
    "active": true,
    "firstName": "Fred",
    "lastName": "Flintstone",
    "title": "Mr",
    "email": "fred.flintstone@slaterockandgravel.com",    
    "personTypeId": 2,
    "personType": {
      "id": 2,
      "name": "Blue-Collar"
    },
    "personCoins": [
      {
        "id": 118,
        "lastModifiedDate": "2019-05-12T23:01:33.1566667",
        "active": true,
        "fullYearValue": 102.0,        
        "personId": 1,        
        "financialYearId": 19,
        "financialYear": {
          "id": 19,
          "lastModifiedDate": "2019-04-30T15:33:20.05",
          "active": true,
          "startDate": "2019-05-01T00:00:01",
          "endDate": "2020-04-30T00:00:00",
          "label": "FY 2019/2020"
        }
      }
    ],
    "personLocations": [
      {
        "id": 1,
        "lastModifiedDate": "2019-04-25T10:19:07.193",
        "active": true,
        "startDate": "2018-10-29T09:00:00",
        "endDate": null,
        "office": {
          "id": 2,
          "lastModifiedDate": "2019-04-25T10:16:37.9533333",
          "active": true,
          "name": "Bedrock",
          "address1": "The Quarry",
          "address2": "Bedrock",
          "address3": "Prehistorica",
          "zipcode": "YabbaDabbaDoo",
          "openingDate": "1992-06-01T09:00:00",
          "closingDate": null,
          "officialCurrencyId": 1,
          "officialCurrency": null,
          "countryId": 1,
          "country": null
        }
      }
    ]
  }
]

例如它“只是”返回指定年份的 Coin 数据。

当我在分页的 JQuery 数据表中显示这些数据时,我会立即返回所有结果,并且数据库中有 5000 人,因此会返回一个非常大的 JSON 文件。

有没有一种方法可以在子选择中为此查询添加 Where 子句,或者另一种更有效的获取数据的方法。

感谢您的任何帮助。

【问题讨论】:

  • “我想要延迟加载” - .PersonRepository.GetAll() 是否返回 IQueryable 集合?
  • @demo 是的。它返回一个 DBSet,如下所示: public IQueryable GetAll() { return Dbset; }

标签: c# entity-framework lambda


【解决方案1】:

快速浏览一下,您只需在财政年度部分添加一个 where 子句:

var persons = appCoreDBContext.PersonRepository.GetAll()
              .Where(p => p.Active.Equals(true))
              .Select(pl => new
              {
                 pl,
                 PersonLocs = pl.PersonLocations.Where(ed => ed.EndDate != null)
                 .Select(o => new
                 {
                     o,
                     office = o.Office
                 }),
                 PersonType = pl.PersonType,
                 PersonCoins = pl.PersonCoins
                 .Where(yr => yr.FinancialYear != null)
                 .Select(yr => new
                 {
                     yr,
                     finYear = yr.FinancialYear
                 })
                 .Where(ee => ee.finYear.StartDate.Year == DateTime.Now.Year)
              })
              .AsEnumerable()
              .Select(x => x.pl);

【讨论】:

  • 嗨。这似乎根本没有任何区别。带回来的结果是一样的。我明白你在暗示什么。谢谢,安东尼
【解决方案2】:

问题是您正在尝试对数据进行子过滤,但最后您选择并使用 .Select(x => x.pl) 序列化完整的 Person 实体及其所有相关实体

试试这个:

.Select(pl => new PersonViewModel
{
    pl.id,
    pl.lastModifiedDate,
    pl.active,
    pl.firstName,
    pl.lastName,
    pl.email,
    pl.personType.Select(pt => new PersonTypeViewModel
    {
       pt.id,
       pt.name
    }),             
    personLocs = pl.PersonLocations.Where(ed => ed.EndDate != null)
        .Select(o => new PersonLocationViewModel
        {
           id = o.OfficeId,
           office = o.Office
        }),
    personCoins = pl.PersonCoins
       .Select(yr => new PersonCoinViewModel
       {
           finYear = yr.FinancialYear
       })
       .Where(ee => ee.finYear.StartDate.Year == DateTime.Now.Year)
 }).AsEnumerable();

您需要为要发回的数据结构定义视图模型,因为我不相信您可以返回/序列化匿名类型。

基本上只选择您想要的字段和相关数据而不选择实体。您应该避免返回实体,包括在返回的 DTO/ViewModel 中引用实体,因为这将包括序列化实体中可用的所有数据和相关数据。这可能会触发延迟加载(性能问题)并向客户端发送比您需要或希望暴露给潜在恶意用户的更多数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-14
    • 2016-01-04
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    • 2021-12-15
    • 2013-01-07
    • 2015-03-15
    相关资源
    最近更新 更多