Eloquent 是Laravel内置的一个功能强大的数据库关系映射器,通过use Illuminate/Database/Eloquent/Model;引用其内置的各项强大的方法对数据库实现更优雅的CRUD操作。
Eloquent和前面说到的查询构造器功能相似,Eloquent的出现是为了让程序员只需要注重代码层面的工作,无需过多的了解SQL语言,Laravel将我们常用的SQL语句封装成了可以通过语义变成更可读的程序操作。
下面列出常用的模型方法,以快速了解我们的需要,并对照官方文档了解详细使用方法:
ORM用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。Laravel对语法深入优化,所以在执行效率上更接近原生SQL,与查询构造器的区别基本上就只有在程序逻辑层面,在使用了Opcache的情况下效果几乎感觉不到差异,所以为了我们更高的可维护性与编程,我们更应该去使用Eloquent。
在使用Eloquent前我们需要有一些前置准备条件,与查询构造器一样,首先我人需要保证其数据库连接的可用性。然后根据下面的步骤对MVC构架做初始化的工作。
请先使用数据库迁移功能创建Model与迁移表,并使用命令创建我们将要操作的数据表工作,参考:http://www.55mx.com/php/209.html
通过上面提供的参考方法创建了一个模型和其关联的数据库表后,就可以开始从数据库中检索数据了。
我们可以将Eloquent视为一个强大的 查询构建器 ,可以让我们流畅的查询与模型关联的数据表,模型中的all方法可以从模型的关联数据库表中检索出所有的记录:
use AppModelsSetting; //引入我们准备工作里的模型
class ShowController extends Controller
{
public function show()
{
//Setting::all() = select * from settings
foreach (Setting::all() as $setting) { //返回一个查询结果对象
echo $setting->key;//使用对象属性 访问键值
echo $setting->value;
}
}
}
上面控制器代码里可以看到没有一行SQL语句的影子,但从数据库里获取到了设置项的所有内容。Eloquent 的 all() 方法会返回模型中所有的结果。
小提示:使用Setting::all()与Setting::get()得到的结果是一模一样的,并且生成的查询语句也是一样的,它们的区别在于Setting::all()是一个快速方式,直接返回了查询后的结果集,中间不能再使用排序、条件等限制,而下面我们要使用的Setting::get()方法则更灵活,所以它们的区别在于是否可以附件更多的条件限制。
由于每个 Eloquent 模型都可以被视为 查询构造器,可以添加额外的查询条件,然后使用 get() 方法获取查询结果:
public function show()
{
$Setting = Setting::where('value', 1) //查询value = 1的数据
->orderBy('key') //使用key排序
->take(10) //返回10条数据
->get(); //查询结果转对象
//->toSql(); //select * from `kwok_settings` where `value` = ? order by `key` asc limit 10
return $Setting->toJson(); //使用集合辅助功能转为Json
}
Eloquent Collection 类扩展了 Laravel 的 Illuminate/Support/Collection 基类,它提供了 大量的辅助方法 来与数据集合交互。
如果已经有一个从数据库中检索到的 Eloquent 模型的实例,你可以使用 fresh 和 refresh 方法「刷新」模型。 fresh 方法将从数据库中重新检索模型。现有模型实例不会受到影响:
public function show()
{
$Setting = Setting::where('value', '>', 1)->first();
echo $Setting->key; //输出数据库里的结果
echo $Setting->key = '改了';//输出修改后的结果
$freshSetting = $Setting->fresh(); //将刷新后的模型(重新执行Sql语句)交给新的变量
echo $freshSetting; //打印新变量的结果(数据库里的结果)
}
上面代码里我们将重新查询的结果赋予了新的变量,如果我只想要直接刷新当前的模型,只需要使用refresh即可,上面的代码重写为:
public function show()
{
$Setting = Setting::where('value', '>', 1)->first();
echo $Setting->key; //输出数据库里的查询结果
echo $Setting->key = '改了'; //输出修改后的结果
$Setting->refresh(); //直接当前模型刷新模型(重新执行Sql语句)
echo $Setting; //输出结果(数据库里的结果)
}
refresh 方法会使用数据库中的新数据重新赋值现有的模型。此外,已经加载的关系也会被重新加载。Eloquent 是继承于 IlluminateDatabaseEloquentCollection 集合,并扩展了自己一些独有的方法。
当前我们查询的表里数据量过大时,使用->all()方法或者get()方法的时候,会大量占用服务器的资源,和查询构造器一样,Eloquent也提供chunk()方法,使用分块数据查询:
//每次获取10条数据
Setting::chunk(10, function ($settings) {
//获取到数据后传递给闭包处理
echo '<h2>分块了</h2>';
//使用each 代替foreach方法遍历集合
$settings->each(function ($item, $key) {
echo '<li>' . $key . '=>' . $item . '</li>';
});
});
传递给「chunk」方法的第一个参数是每个分块检索的数据数量。第二个参数传递的闭包将方法将应用到每个分块,以数据库中查询到的分块结果来作为参数。
如果要根据一个字段来过滤「chunk」方法拿到的数据,同时,这个字段的数据在遍历的时候还需要更新的话,那么可以使用「chunkById」方法。在这种场景下如果使用「chunk」方法的话,得到的结果可能和预想中的不一样。在「chunkById」 方法的内部,默认会查询 id 字段大于前一个分块中最后一个模型的 id。
Setting::where('value', true)
->chunkById(10, function ($setting) {
echo $setting;//输出查询结果
}, $column = 'key');
使用惰性lazy()方法在后台以块的形势执行查询操作,lazy不是将每个块直接传递到闭包回调中,而以返回 Eloquent 模型的扁平化 LazyCollection,它可以让你将结果作为单个流进行交互:
echo '<ol>';
foreach (Setting::lazy() as $setting) {
echo '<li>' . $setting . '</li>';
}
如果要根据一个字段来过滤「lazy」方法拿到的数据,同时,这个字段的数据在遍历的时候还需要更新的话,那么可以使用「lazyById」方法。在「lazyById」 方法的内部,默认会查询 id 字段大于前一个「chunk」中最后一个模型的 id 。
Setting::where('value', 1)
->lazyById(10, $column = 'key')
->each(function ($item) {
echo '' . $item . '';
});
lazy使用可以用于加载数据关系,并有很好的性能,比较推荐使用!
与 lazy 方法类似,cursor 方法可用于在查询数万条 Eloquent 模型记录时减少内存的使用。
cursor 方法只会执行一次数据库查询;但是,各个 Eloquent 模型在实际迭代之前不会被数据填充。因此,在遍历游标时,在任何给定时间,只有一个 Eloquent 模型保留在内存中。
foreach (Setting::where('value', '1')->cursor() as $setting) {
echo $setting;
}
cursor 方法一次只能在内存中保存一个 Eloquent 模型。使用后就自由回收内存。但值得注意的是在查询大量数据时它最终仍会耗尽内存。如果要处理大量 Eloquent 记录,请考虑使用上面的 lazy 方法。
相比上面的查询,插入、修改与删除要简单许多,也提供了封装好的各种方法供我们使用。
只需要实例化一个新模型实例并在模型上设置属性。然后,在模型实例上调用 save 方法:
$setting = new Setting;//初始化一个Setting实例
$setting->key = 'imgzip';//图片压缩
$setting->value = 95;//图片压缩率
$setting->save();//保存修改
使用create方法可以快捷操作插入,如果我们未设置的情况下,这2个方法都会自动维护updated_at与created_at字段:
$setting = Setting::create([
'key' => 'wapurl',
'value' => 'https://m.meishiq.com/',
]);
//使用create方法将自动写入到数据表里,无需调用 save方法
以上2种插入数据的方式,可以根据我们的需求选择,一般情况第一种方式更适用于需要修改Model参数时使用($setting->timestamps = true)。同时下面的更新操作也是使用此方式。
我们在更新数据之前,应该先根据条件查找到需要更新的内容:
$setting = Setting::find('timeoffset');//查找到key = timeoffset的值
$setting->value = 8;//修改时区
$setting->save();//保存修改
当$timestamps=true时,此操作会自动维护updated_at字段的时间。
除了上面的单个数据更新,我们也可以使用批量的更新操作:
Setting::where('value', 1) //找到所有value=1的值
->update(['value' => -1]);//改为:-1
update 方法需要一个表示应该更新的列的列和值对数组。 update 方法返回受影响的行数。
注意:通过 Eloquent 批量更新时,不会触发模型的 saving、saved、updating 和 updated 模型事件。 这是因为在批量更新时从未真正检索到模型。
有时候,我们需要使用一个值插入到数据库里,如果此值存在的情况下,我们就更新,否则插入,这样我们就需要updateOrCreate方法来实现:
$setting = Setting::updateOrCreate(
['sitemap_num' => 10000],//单个文件生成sitemap的数量
['price' => 99]//商品价格
);
删除操作提供了多种灵活的方式,我们可以根据情况选择性使用:
//查询并删除
$Setting = Setting::find('url');
$Setting->delete();
//按条件批量删除
$deleted = Setting::where('value', 0)->delete();//删除所有value=0的值
通过主建删除:
Setting::destroy('imgzip');//单个删除
//多个删除
Setting::destroy('url','wapurl');
Setting::destroy(['url','wapurl']);
Setting::destroy(collect(['url','wapurl']));
清空表:
Setting::truncate();//清空此表自增ID初始化
上面的方式是直接将数据从表中清除,但有时候我们还希望能恢复被删除的数据,所以我们需要在表中指定一个字段:deleted_at,以记录软删除的时间。
如果要使用软删除功能,我们需要在Model里打开属性开关:
use IlluminateDatabaseEloquentSoftDeletes;//使用软删除
class Setting extends Model
{
use SoftDeletes;//打开软删除开关
}
//技巧:SoftDeletes trait 会自动将 deleted_at 属性转换为 DateTime / Carbon 实例。
然后需要增加软删除必备的字段,下面以迁移演示:
Schema::table('Setting', function (Blueprint $table) {
$table->softDeletes();
});
Schema::table('Setting', function (Blueprint $table) {
$table->dropSoftDeletes();
});
判断是否被软删除,可以使用trashed方法:
if ($setting->trashed()) {
//被删除了
$setting->restore();//恢复被删除
}
批量恢复被软删除的数据:
Setting::withTrashed()
->where('value', 1)
->restore();
//和其他「批量」操作一样,这个操作不会触发模型的任何事件
$setting->history()->restore();//可以在 关联查询 中使用
将软删除的数据真正删除:
$setting->forceDelete();//硬删除所有被软删除的数据
$setting->history()->forceDelete();//在关联查询上使用
软删除并不是真正的删除,只是标记了删除时间,当使用模型查询数据时,将自动排队被软删除的数据。
模型虽好用,但查询语法并不是最优化的,我们应该尽量避免使用一些大量耗费服务器资源的查询,下面个人总结了一些查询优化以供参考:
上面语句大部分都是使用select * 来查询数据库的,很多时候我们并不需要 这么多的字段,所以我们可以使用select方法限制查询的字段:
echo Setting::select('key', 'value')->where('value', '1')->toSql();
//select `key`, `value` from `kwok_settings` where `value` = ?
使用all、get、first时可以使用参数限制column字段名:
Setting::all('key', 'value');//select `key`, `values` from `kwok_settings`
Setting::get(['key', 'value']);//select `key`, `values` from `kwok_settings`
//find方法限制字段
Setting::find(['allowcache', 'sitename', 'seotitle'], ['key', 'value']);
//select `key`, `value` from `kwok_settings` where `kwok_settings`.`key` in (allowcache, sitename, seotitle)
//获取单个字段时使用
Setting::where('key', 'allowcache')->value('value');
//select `value` from `kwok_settings` where `key` = allowcache limit 1
//使用pluck方法限制
Setting::where('key', 'allowcache')->pluck('key', 'values');
//select `key`, `values` from `kwok_settings` where `key` = allowcache
//使用findOrFail的第二个参数
Setting::findOrFail('allowcache', ['key', 'value']);
//select `key`, `value` from `kwok_settings` where `kwok_settings`.`key` = allowcache limit 1
获取查询语句的小技巧:我在网上搜索了很多,有的推荐使用toSql()方法,但很多都不能获取,所以我故意将字段写错,比如上面的value我改成values时Laravel就会报错,在错误里就可以看到SQL语句了。
如果你有更好的查询语句获取方法,可以通过评论告诉我。
除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:https://www.55mx.com/post/208
《【Laravel笔记】内置数据库关系映射器(ORM): Eloquent 使用快速入门》的网友评论(0)