在 Laravel 项目里,操作数据库不一定要直接写大量 SQL。Eloquent ORM 提供了一种更接近面向对象的写法,可以把数据表映射成模型,让开发者通过模型完成查询、新增、修改、删除和关联数据读取。对于中小型后台、内容系统、接口项目和管理平台来说,Eloquent 是 Laravel 开发中非常常用的一部分。
一、Eloquent ORM 是什么
ORM 是 Object Relational Mapping 的缩写,意思是对象关系映射。简单说,就是把数据库表和 PHP 类对应起来,把表中的一行数据对应成一个模型对象。
例如,数据库中有一张 posts 表,就可以创建一个 Post 模型。之后查询文章时,不必每次手写 SQL,可以直接使用:
$posts = Post::where('status', 1)->get();
这种写法更符合 Laravel 的开发习惯,也更容易和控制器、服务层、API 返回数据结合。
二、创建 Eloquent 模型
可以使用 Artisan 命令创建模型:
php artisan make:model Post
执行后会生成:
app/Models/Post.php
模型文件示例:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = [
'title',
'content',
'status',
];
}
$fillable 用来定义允许批量赋值的字段。这样在创建或更新数据时,可以避免不希望被用户提交修改的字段被写入。
如果想同时创建模型和迁移文件,可以执行:
php artisan make:model Post -m
三、模型和数据表的对应关系
Laravel 默认会把模型类名转换为复数形式的数据表名。
例如:
Post模型默认对应posts表。User模型默认对应users表。Category模型默认对应categories表。
如果数据表名称不符合 Laravel 默认规则,可以在模型中指定:
class Post extends Model
{
protected $table = 'article_posts';
}
如果主键不是 id,也可以指定:
protected $primaryKey = 'post_id';
如果表里没有 created_at 和 updated_at 字段,可以关闭时间戳:
public $timestamps = false;
四、使用 Eloquent 查询数据
Eloquent 提供了常用的数据查询方法。
查询全部数据:
$posts = Post::all();
按条件查询:
$posts = Post::where('status', 1)->get();
查询单条数据:
$post = Post::find(1);
如果找不到数据就抛出异常:
$post = Post::findOrFail(1);
排序查询:
$posts = Post::where('status', 1)
->orderBy('created_at', 'desc')
->get();
分页查询:
$posts = Post::where('status', 1)->paginate(10);
在列表页、后台管理页和 API 数据接口中,分页查询非常常用。
五、新增数据
新增数据可以使用 create 方法:
$post = Post::create([
'title' => 'Laravel Eloquent 入门',
'content' => '这里是文章内容',
'status' => 1,
]);
使用 create 时,需要在模型中配置 $fillable,否则可能无法批量写入。
也可以使用对象方式新增:
$post = new Post();
$post->title = 'Laravel Eloquent 入门';
$post->content = '这里是文章内容';
$post->status = 1;
$post->save();
对象方式更直观,适合需要逐步处理字段的场景。
六、更新数据
更新单条数据可以先查询,再修改:
$post = Post::findOrFail(1);
$post->title = '新的文章标题';
$post->save();
也可以使用批量更新:
Post::where('status', 0)->update([
'status' => 1,
]);
批量更新适合后台批处理,但要注意条件范围,避免误改大量数据。
七、删除数据
删除单条数据:
$post = Post::findOrFail(1);
$post->delete();
按条件删除:
Post::where('status', 0)->delete();
如果项目需要保留删除记录,可以使用软删除。模型中引入 SoftDeletes:
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
use SoftDeletes;
}
同时需要在数据表中增加 deleted_at 字段:
$table->softDeletes();
软删除后,数据不会立刻从数据库中物理删除,而是记录删除时间。适合文章、订单、用户等需要恢复或审计的数据。
八、一对一关联
一对一关联适合两个表之间一条数据对应一条数据的关系。
例如,一个用户对应一个用户资料:
class User extends Model
{
public function profile()
{
return $this->hasOne(Profile::class);
}
}
在 Profile 模型中可以写:
class Profile extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
使用时:
$user = User::find(1);
$profile = $user->profile;
九、一对多关联
一对多是项目中非常常见的关系。例如,一个分类下有多篇文章。
在 Category 模型中:
class Category extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
}
在 Post 模型中:
class Post extends Model
{
public function category()
{
return $this->belongsTo(Category::class);
}
}
使用时:
$category = Category::find(1);
$posts = $category->posts;
或者查询文章所属分类:
$post = Post::find(1);
$category = $post->category;
十、多对多关联
多对多适合一个模型可以关联多个模型,另一个模型也可以反向关联多个模型的场景。
例如,一篇文章可以有多个标签,一个标签也可以属于多篇文章。
在 Post 模型中:
class Post extends Model
{
public function tags()
{
return $this->belongsToMany(Tag::class);
}
}
在 Tag 模型中:
class Tag extends Model
{
public function posts()
{
return $this->belongsToMany(Post::class);
}
}
Laravel 默认会使用中间表,例如 post_tag。如果中间表名称不同,可以在 belongsToMany 中指定。
return $this->belongsToMany(Tag::class, 'post_tag');
给文章绑定标签:
$post = Post::find(1);
$post->tags()->attach([1, 2, 3]);
同步标签:
$post->tags()->sync([2, 3, 4]);
sync 会让关联关系与传入数组保持一致,常用于后台编辑表单。
十一、避免 N+1 查询问题
使用模型关联时,要注意 N+1 查询问题。
例如:
$posts = Post::all();
foreach ($posts as $post) {
echo $post->category->name;
}
如果有 100 篇文章,这种写法可能会额外查询 100 次分类。更好的方式是使用预加载:
$posts = Post::with('category')->get();
预加载可以减少数据库查询次数,提高列表页和接口性能。
多个关联也可以一起加载:
$posts = Post::with(['category', 'tags'])->get();
十二、Eloquent 使用注意事项
使用 Eloquent 时,建议注意以下几点:
- 查询列表时尽量使用分页,不要一次取出大量数据。
- 批量赋值时配置 $fillable,避免字段被意外写入。
- 关联查询时注意预加载,避免 N+1 查询。
- 大批量数据处理可以使用 chunk 分批读取。
- 复杂统计和性能敏感查询,可以结合查询构造器或原生 SQL。
- 不要把所有业务逻辑都堆进模型,复杂项目应合理拆分服务层。
Eloquent 写法简洁,但并不代表所有查询都要用模型强行完成。对于复杂报表、聚合统计和大数据量场景,仍然需要结合实际性能选择合适方案。
十三、常见问题
Eloquent 和 Query Builder 有什么区别?
Eloquent 是 ORM,围绕模型对象操作数据;Query Builder 更接近 SQL 构造器,适合灵活拼接查询。普通业务表适合用 Eloquent,复杂查询或性能敏感场景可以考虑 Query Builder。
Eloquent 模型必须和数据表同名吗?
不必须。Laravel 有默认命名规则,但可以通过 $table 指定模型对应的数据表。
为什么 create 方法写入失败?
常见原因是模型没有配置 $fillable,或者字段不在允许批量赋值范围内。也可能是数据库字段约束不允许为空。
Eloquent 适合大型项目吗?
适合,但要注意查询优化、关联预加载和业务分层。大型项目中通常不会把所有逻辑都写在模型里,而是结合服务层、仓储模式或查询对象管理复杂逻辑。

