Laravel DB门面和Eloquent模型的查询及差异

30 阅读4分钟

目录

一. DB门面(查询构建器)

1.查询实例

查询实例对象解析:

返回的实例对象为Illuminate\Database\Query\Builder

$result = DB::table("表名");

 // 打印$result结果
Illuminate\Database\Query\Builder {
   ... 
}

切换多数据库:

可使用connection()方法选择指定的数据库,返回实例也为 Illuminate\Database\Query\Builder,因为此调用first()get()等方法得到的结果与直接使用DB::table("表名")调用一样;

$result = DB::connection('数据库连接别名')->table("表名");

// 打印$result结果
Illuminate\Database\Query\Builder {

}

2. 常用查询方法

get()方法详解

  • 返回数据类型:
    结果集是一个Illuminate\Support\Collection对象实例, 其中每个子项都是实际上是PHP StdClass对象的一个实例

    // 查询方法
    $data = DB::table('user')->whereIn('id', [1,2])->get();
    
    // 取值结果
    foreach($data as $da) {
       $userId = $da->id; //  子项都是对象,只能采用对象取值
    }
    

    有值返回的打印结果

    Illuminate\Support\Collection^ {#2184
       #items: array:2 [
          0 => {#2195
             +"id": 1
          }
          1 => {#2186
             +"id": 2
          }
       ]
    }
    

    无值返回的结果

    Illuminate\Support\Collection^ {#2184
       #items: []
    }
    
  • 空结果判断:
    可以通过isEmpty()方法判断是否存在数据对象, 存在为false, 不存在为true

  • 结果集转化为二维数组:
    ❌ 错误方式: 使用get()->toArray(), 会得到一个数组,但数组子元素还是StdClass对象的实例, 查询无结果时为空数组;

    # 返回值
    array:2 [
       0 => {#2195
          +"id": 1
       }
       1 => {#2186
          +"id": 2
       }
    ]
    
    $data = DB::table('user')->select(['id'])->get()->toArray();
    
    // 因此只能用对象取值法
    foreach ($data as $da) {
       $userId = $da->id; 
    }
    

    ✅ 正确方式: 可采用map()方法,将数据子项对象强制转化为数组。

    $data = DB::table('user')->select(['id'])->get()->map(function($item) {
       return (array)$item;
    })->toArray();
    
    // 数组可直接使用empty()判断是否有数据
    if (empty($data)) {
       return "暂无数据";
    }
    
    foreach ($data as $da) {
       $userId = $da['id']; // 采用数组方式取值,无法通过对象取值了
    }
    

first()方法详解

  • 返回数据类型:
    查询有结果时,返回一个StdClass对象实例;查询无结果时返回null;

    $info = DB::table('user')->where('id', 1)->first();
    
    # 返回值结果
    {#2197
          +"id": 1
          +"name": "demo"
    }
    
  • 空结果判断:
    可以通过empty()方法判断是否存在数据对象, 存在为false, 不存在为true

  • 转化为二维数组: 可以通过->toArray()转化,先判断是否为空再进行转化,否则会报错

    $data = User::where('id', 1)->first();
    $data = $data ? $data->toArray() : [];
    
  • 变形语法:
    简写化写法find(), find(1)等价于->where('id',1)->first()

二. Eloquent ORM(模型查询)

1. 查询实例

查询实例对象解析:

返回的实例对象为Illuminate\Database\Eloquent\Builder

$result = User::query();

// 打印result结果
Illuminate\Database\Eloquent\Builder^ {#2188
   ...   
}

两种语法:

// 常用写法
$result = User::where('id', 1);

// 等价于上面的语法,返回实例相同,是上面语法的完整版
$result = User::query()->where('id', 1);

切换多数据库:

通过模型类中$connection 属性来控制数据库切换

2. 常用查询方法

get()方法详解

  • 返回数据类型:
    结果集是一个Illuminate\Database\Eloquent\Collection对象,其子项是模型对象实例,例如 App\Model\User

    // 查询方法
    $data = User::whereIn('id', [1, 2])->get();
    
    // 取值结果 (数组或对象取值都可以)
    foreach ($data as $da) {
       $userId = $da->id;
       $userName = $da['name'];
    }
    

    有值返回的打印结果

    Illuminate\Database\Eloquent\Collection^ {#2203
       #items: array:2 [
          0 => App\Model\User^ {#2204
             #table: "user"
             #guarded: []
             +timestamps: false
             #connection: "mysql"
             #primaryKey: "id"
             #keyType: "int"
             +incrementing: true
             #with: []
             #withCount: []
             #perPage: 15
             +exists: true
             +wasRecentlyCreated: false
             #attributes: array:24 [
                "id" => 1
                "name" => "测试"
             ]
             #original: array:24 [
                "id" => 1
                "name" => "测试"
             ]
             #changes: []
             #casts: []
             #dates: []
             #dateFormat: null
             #appends: []
             #dispatchesEvents: []
             #observables: []
             #relations: []
             #touches: []
             #hidden: []
             #visible: []
             #fillable: []
          }
       ]
    }
    
  • 空结果判断 可以通过isEmpty()方法判断是否存在数据对象, 存在为false, 不存在为true

  • 结果转化为二维数组 使用get()->toArray(),有值返回的标准的二维数组,无值返回空数组

first()方法详解

  • 返回数据类型:
    查询有结果时,返回一个模型对象实例; 查询无结果时返回null;
  • 空结果判断 可以通过empty()方法判断是否存在数据对象, 存在为false, 不存在为true
  • 转化为二维数组: 可以通过->toArray()转化,先判断是否为空再进行转化,否则会报错
    $data = User::where('id', 1)->first();
    $data = $data ? $data->toArray() : [];
    

三. 两者的区别和避坑点

1. DB门面和与模型查询实例的关联和区别

对比关系

维度DB门面模型Eloquent
返回实例Illuminate\Database\Query\BuilderIlluminate\Database\Eloquent\Builder
内存占用较低(StdClass对象)较高(模型对象)
查询复杂度适合简单查询支持复杂模型关联

2. 典型报错场景与解决方案

问题: 模型类取实例属性时例如已设置的分组字段groups 会出现报错 Exception: Property [groups] does not exist on the Eloquent builder instance

  • 原因: 模型类是基于查询构造器实例的基础上封装,它无法直接获取查询构造器中的属性
  • 解决方法: 通过调用getQuery(),获取基础的查询构造器实例,然后再获取属性。从而获取关键属性信息如分组字段groups、查询字段columns、排序字段orders
$builder = User::query();
// 会报错
$builder->groups;

// 正确做法, 此时会调用查询构造器实例
$builder->getQuery()->groups;