在我的应用程序中,我有下表:
CREATE TABLE files (
id bigint IDENTITY(1,1) NOT NULL,
name nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
folder bigint NULL,
[type] nvarchar(10) NOT NULL CHECK ([type] IN ('FILE', 'FOLDER')) DEFAULT 'FOLDER',
CONSTRAINT PK__3213E83FDB19A582 PRIMARY KEY (id),
CONSTRAINT folder_fk FOREIGN KEY (folder) REFERENCES files(id),
);
create table files_closure (
ancestor bigint NOT NULL,
decedant bigint NOT NULL,
"depth" int NOT NULL,
CONSTRAINT files_closure_pk PRIMARY KEY (ancestor,decedant),
CONSTRAINT files_closure_ancestor_fk FOREIGN KEY (ancestor) REFERENCES files(id),
CONSTRAINT files_closure_decedant_fk FOREIGN KEY (decedant) REFERENCES files(id),
);
每个桌子也有自己的模型:
文件
class Files extends Model
{
protected $table='files';
public $timestamps = false;
public function parentFolder():HasOne
{
return $this->hasOne(self::class,'id','folder');
}
public function files(): HasMany
{
return $this->hasMany(self::class, 'folder');
}
}
对于关闭表:
class FilesClosure extends Model
{
protected $table='files_closure';
public $timestamps = false;
public function ancestor():HasOne
{
return $this->hasOne(Files::class,'ancestor','id');
}
public function decedant():HasOne
{
return $this->hasOne(Files::class,'ancestor','id');
}
}
我想尽可能快地创建一个json结构(在最少的执行时间内而不造成数据库开销):
{
files: [
{
name:"My Music",
type: "FOLDER",
files: [
{
name: "Halford",
type: "FOLDER",
files: [
{
name: "Locked-and-loaded.mp3",
type: "FILE"
},
{
name: "Another Song.mp3",
type: "FILE"
}
]
}
]
}
]
}
如果我避免使用闭包表,我可以将数据检索为:
$json = Files::with('parentFolder','files')->whereNull('folder')->get()->toJson();
但这会导致多个查询,并且响应时间很慢,尤其是在大型数据集上。因此我想使用闭包表,但我不知道如何做到这一点。
检查下面我修改了 Laravel
Files
模型以使用闭包表有效处理分层数据的位置。该方法涉及单个查询,该查询将 files
表与 files_closure
表连接起来以检索分层数据,同时尊重文件夹文件结构。然后在 PHP 中处理该数据以构建树状结构。 getHierarchicalData
模型中的静态方法 Files
获取数据,另一组方法 buildTree
和 buildBranch
用于将此数据组织成嵌套树格式,反映文件夹-文件层次结构。这种方法最大限度地减少了数据库查询次数,特别有利于大型数据集,并且最终的树结构转换为 JSON 格式,适合所需的输出。
class Files extends Model
{
protected $table = 'files';
public $timestamps = false;
// New method to retrieve hierarchical data
public static function getHierarchicalData()
{
// Get hierarchical data
$data = DB::table('files as f')
->join('files_closure as fc', 'f.id', '=', 'fc.decedant')
->select('f.*', 'fc.ancestor', 'fc.depth')
->orderBy('fc.ancestor')
->orderBy('fc.depth')
->get();
return self::buildTree($data);
}
protected static function buildTree($data)
{
$items = [];
foreach ($data as $item) {
$items[$item->ancestor][] = $item;
}
$tree = self::buildBranch($items, null);
return $tree;
}
protected static function buildBranch(&$items, $parentId)
{
$branch = [];
foreach ($items[$parentId] as $item) {
if (isset($items[$item->id])) {
$item->files = self::buildBranch($items, $item->id);
} else {
$item->files = [];
}
$branch[] = $item;
}
return $branch;
}
}
在控制器中,您调用:
$json = json_encode(Files::getHierarchicalData());