【问题标题】:Silverstripe 3.5 - How to query for specific columns and return an arraySilverstripe 3.5 - 如何查询特定列并返回一个数组
【发布时间】:2017-10-18 04:24:48
【问题描述】:

我正在尝试全选以从单个表中获取三列,然后简单地将结果用作数组。无需花费循环。

我已经尝试过使用 ORM 方法:

DataObject::get('City')->sort('Name ASC')->toNestedArray();

这给了我一个完美的数组。但我看不到只返回我想要的列的方法。它返回所有列。这是一个问题,因为我正在对这个数组进行 json 编码,因此数据包是它所需大小的 3 倍。

所以我改用 SQLQuery 进行了尝试:

DB::query('SELECT "ID","Name","ParentID" FROM "City"');

现在这允许我选择三个字段,但据我所知,没有任何方法可以将此查询作为数组返回,如 toNestedArray()

搜索了高低,但没有合适的。有任何想法吗?

编辑:应该提到我已经尝试过 setQueriedColumns() 抱歉。这似乎不适用于我在这里所做的事情。

$cities = AspireCity::get()->sort(['Name' =>  'ASC'])->setQueriedColumns(['ID', 'Name']);
Debug::dump($cities->toNestedArray());

输出:

Array
(
    [0] => Array
        (
            [ClassName] => City
            [LastEdited] => 2017-09-26 11:14:16
            [Name] => Acacia Bay
            [ID] => 70
            [RecordClassName] => City
            [Created] => 
            [ParentID] => 9
        )

    [1] => Array
        (
            [ClassName] => City
            [LastEdited] => 2017-09-26 11:14:16
            [Name] => Ahaura
            [ID] => 71
            [RecordClassName] => City
            [Created] => 
            [ParentID] => 9
        )

【问题讨论】:

  • 谢谢。我确实尝试过,但似乎没有按预期工作。有关详细信息,请参阅我的问题的编辑。也许 toNestedArray() 会忽略它?
  • 我很确定在使用 ORM 时,始终会输出数据对象系统字段。这些是 ClassName、LastEdited、ID、Created。 setQueriedColumns 然后允许您选择已添加到 DataObject 模型中的字段。如果您只需要字段 ID、名称、ParentID,您将需要使用 sql 查询,就像您在下面的答案中所做的那样。
  • 如果 DataObject 不存在,silverstripe 不会延迟加载数据,因此调用 toNestedArray 肯定会触发每次迭代的所有值的加载,但不记得只会调用属于该查询还导致加载其余丢失的 DO 数据。

标签: php silverstripe


【解决方案1】:

根据API DocssetQueriedColumns()是你的朋友:

根据您的问题,我假设您要查询的 DataObject 名为 City,因此我们需要这个来将所有城市从数据库中取出:

City::get();

这将返回一个DataList 并在您需要时查询数据库。到目前为止,您的数据库不知道您想要从中获取一些数据的任何内容。因此,让我们对其进行细化,按“名称”ASC 对其进行排序。我更喜欢数组语法,恕我直言,它更易于阅读,如果您需要对第二行进行排序,只需将其添加到数组中:

City::get()
    ->sort(['Name' =>  'ASC']);

现在,出于某些原因,您希望只返回一些列。由于我不知道您的 City DataObject 有哪些数据库字段,我假设您只需要“名称”和“ZIP”:

City::get()
    ->sort(['Name' =>  'ASC'])
    ->setQueriedColumns(['Name', 'ZIP']);

这限制了查询的列,您可以添加toNestedArray() 以将数据作为纯老式数组取出。这可能有助于将数据传递给 API,但最好保留对象并在代码中使用城市特定的逻辑。

【讨论】:

  • 对不起,我应该提到我查看了 setQueriedCoumns。我认为这无关紧要。似乎没有达到这个目的 $cities = City::get()->sort(['Name' => 'ASC'])->setQueriedColumns(['ID', 'Name']);调试::转储($cities->toNestedArray());输出表中的所有字段
  • 您可以通过将->sql() 添加到DataList 来查看生成的查询。我的猜测是,它首先会减少查询,但是当您运行 toNestedArray() laster 时,它会获取其他列。
  • Na 我实际上在没有使用 toNestedArray() 的情况下测试了 List 上的循环,所有字段都在那里。不知道为什么 setQueriedColumns 似乎没有按照它说的去做。就我而言,它没有。
  • 你检查生成的SQL查询了吗? DataObject 可能会在稍后需要时延迟加载其他字段
【解决方案2】:

所以我认为这是过度依赖现有 SS 辅助方法的情况。虽然 toNestedArray() 非常方便,但我对它的关注主要是基于我可以通过使用它来避免循环的想法。在现实中,该方法当然是一个循环。所以真的我的担心是没有根据的。

最重要的目标是在查询时减少数据集。所以解决方案只是专注于此。

// Inject the default country/city/suburb data as vars so they can be easily filtered.
$location['countries'] = DB::query('SELECT "ID","Description" FROM "Country" ORDER BY "ID" ASC'); 
$location['cities'] = DB::query('SELECT "ID","Name","ParentID" FROM "City" ORDER BY "Name" ASC'); 
$location['suburbs'] = DB::query('SELECT "ID","Name","ParentID" FROM "Suburb" ORDER BY "Name" ASC');

$masterLocationArray = [];
foreach($location as $key => $data) {
    $locationArray = [];
    foreach($data as $item) {
        $locationArray[] = $item;
    }
    $masterLocationArray[$key] = $locationArray;
}

// $masterLocationArray is our filtered, tidy array. Do stuff with it

【讨论】:

  • 我建议您在原始数据库查询上使用SQLSelect。它将确保与不同 RDBM 的兼容性并降低注入攻击的风险。
  • 好主意。谢谢。
猜你喜欢
  • 2012-03-12
  • 1970-01-01
  • 2010-11-12
  • 1970-01-01
  • 2017-04-13
  • 1970-01-01
  • 2022-11-08
  • 2014-10-21
  • 1970-01-01
相关资源
最近更新 更多