You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel与Adonis中单一User表按角色关联不同模型的可行性

单表按角色拆分关联模型的实现方案(Laravel & Adonis)

Laravel 实现方式

完全可以实现,推荐两种常用方案:

1. 带角色约束的关联方法

直接在User模型中定义关联,并通过where条件限制仅对应角色的用户能获取关联数据:

// app/Models/User.php
public function posts()
{
    // 仅consumer角色用户能获取关联的Post
    return $this->hasMany(Post::class)->where('role', 'consumer');
}

public function pricing()
{
    // 仅maker角色用户能获取关联的Pricing
    return $this->hasOne(Pricing::class)->where('role', 'maker');
}

使用时,非对应角色的用户调用关联方法会返回空集合,业务层可根据实际场景做判断处理。

2. 单表继承(STI)

创建对应角色的子类模型,继承User并添加全局作用域自动过滤角色,关联逻辑写在子类中,更符合单一职责:

// app/Models/Consumer.php
class Consumer extends User
{
    protected $table = 'users';

    protected static function booted()
    {
        static::addGlobalScope('role', function ($query) {
            $query->where('role', 'consumer');
        });
    }

    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

// app/Models/Maker.php
class Maker extends User
{
    protected $table = 'users';

    protected static function booted()
    {
        static::addGlobalScope('role', function ($query) {
            $query->where('role', 'maker');
        });
    }

    public function pricing()
    {
        return $this->hasOne(Pricing::class);
    }
}

使用时直接通过子类查询:Consumer::find($id)->posts 或 Maker::find($id)->pricing,逻辑更清晰。

AdonisJS 实现方式

同样支持该需求,以下是两种可行方案:

1. 动态条件关联

在User模型中定义动态关联方法,根据当前用户角色返回对应关联或空结果:

// app/Models/User.ts
import { BaseModel, column, hasMany, hasOne, HasMany, HasOne } from '@ioc:Adonis/Lucid/Orm'
import Post from 'App/Models/Post'
import Pricing from 'App/Models/Pricing'

export default class User extends BaseModel {
  @column()
  public role: string

  public async getPosts() {
    if (this.role !== 'consumer') {
      return []
    }
    return this.related('posts').query()
  }

  public async getPricing() {
    if (this.role !== 'maker') {
      return null
    }
    return this.related('pricing').query().first()
  }

  @hasMany(() => Post)
  public posts: HasMany<typeof Post>

  @hasOne(() => Pricing)
  public pricing: HasOne<typeof Pricing>
}

也可以直接在关联的查询回调中添加条件,限制仅对应角色能获取关联数据。

2. 单表继承(STI)

创建角色子类模型,添加全局作用域过滤角色,关联逻辑封装在子类中:

// app/Models/Consumer.ts
import User from './User'
import { scope, hasMany, HasMany } from '@ioc:Adonis/Lucid/Orm'
import Post from './Post'

export default class Consumer extends User {
  public static consumerScope = scope((query) => {
    query.where('role', 'consumer')
  })

  protected static booted() {
    super.booted()
    this.addGlobalScope(this.consumerScope)
  }

  @hasMany(() => Post)
  public posts: HasMany<typeof Post>
}

// app/Models/Maker.ts
import User from './User'
import { scope, hasOne, HasOne } from '@ioc:Adonis/Lucid/Orm'
import Pricing from './Pricing'

export default class Maker extends User {
  public static makerScope = scope((query) => {
    query.where('role', 'maker')
  })

  protected static booted() {
    super.booted()
    this.addGlobalScope(this.makerScope)
  }

  @hasOne(() => Pricing)
  public pricing: HasOne<typeof Pricing>
}

使用时通过子类查询:await Consumer.query().first().then(user => user.posts),自动过滤角色并返回对应关联数据。

内容的提问来源于stack exchange,提问作者toy toy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 05:22:30