go语言orm之gorose全新版本20低调发布

号称go语言版本的laravel's eloquent, 发布了久违了2.0版本, 新版本做了很大的改进和升级, 下面我们一起来看一下新版本的特性. 架构调整gorose 2.0版本做了彻底的重构, 拥有全新的架构. 架构如图: gorose 2.0 采用模块化架构, 通过interface的api通信,严格的上层依赖下层.每一个模块都可以拆卸, 甚至可以自定义为自己喜欢的样子. 主模块 engin gorose 初始化配置模块, 可以全局保存并复用session 真正操作数据库底层模块, 所有的操作, 最终都会走到这里来获取或修改数据orm 对象关系映射模块, 所有的orm操作, 都在这里完成builder 构建终极执行的sql模块, 可以构建任何数据库的sql, 但要符合database/sql包的接口子模块 driver 数据库驱动模块, 被engin和builder依赖, 根据驱动来搞事情binder 结果集绑定模块, 所有的返回结果集都在这里其他语言入手姿势php: 使用过laravel的orm就可以快速上手使用python: 使用过orator orm的用户,可以快速上手ruby: 使用过rails的orm就可以快速上手支持驱动mysql : https://github.com/go-sql-dri... sqlite3 : https://github.com/mattn/go-s... postgres : https://github.com/lib/pq oracle : https://github.com/mattn/go-oci8 mssql : https://github.com/denisenkom... clickhouse : https://github.com/kshvakov/c... 特色连接池链式调用支持传入struct,map或字符串表名读写分离集群支持海量数据自动分块处理一键开启事务,自动回滚和提交模块化架构,自由扩展官方文档最新版2.x文档 api预览db.Table().Fields().Where().GroupBy().Having().OrderBy.Limit().Select()db.Table().Data().Insert()db.Table().Data().Where().Update()db.Table().Where().Delete()最佳实践sql DROP TABLE IF EXISTS "users";CREATE TABLE "users" ( "uid" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" TEXT NOT NULL, "age" integer NOT NULL);INSERT INTO "users" VALUES (1, 'gorose', 18);INSERT INTO "users" VALUES (2, 'goroom', 18);INSERT INTO "users" VALUES (3, 'fizzday', 18);实战代码 ...

June 26, 2019 · 2 min · jiezi

Laravel10个有用的用法

1. 在find方法中指定属性User::find(1, ['name', 'email']);User::findOrFail(1, ['name', 'email']);2. Clone一个Model用replicate方法可以克隆一个Model $user = User::find(1);$newUser = $user->replicate();$newUser->save();3. 判断两个Model是否相同检查两个Model的ID是否相同用is方法 $user = User::find(1);$sameUser = User::find(1);$diffUser = User::find(2);$user->is($sameUser); // true$user->is($diffUser); // false;4. 重新加载一个Model$user = User::find(1);$user->name; // 'Peter'// 如果 name 更新过,比如由 peter 更新为 John$user->refresh();$user->name; // John5. 加载新的Model$user = App\User::first();$user->name; // John//$updatedUser = $user->fresh(); $updatedUser->name; // Peter$user->name; // John6. 更新带关联的Model在更新关联的时候,使用push方法可以更新所有Model class User extends Model{ public function phone() { return $this->hasOne('App\Phone'); }}$user = User::first();$user->name = "Peter";$user->phone->number = '1234567890';$user->save(); // 只更新 User Model$user->push(); // 更新 User 和 Phone Model7. 自定义软删除字段Laravel默认使用deleted_at作为软删除字段,我们通过以下方式将deleted_at改成is_deleted ...

April 21, 2019 · 1 min · jiezi

Laravel 9个不经常用的小技巧

更新父表的timestamps如果你想在更新关联表的同时,更新父表的timestamps,你只需要在关联表的model中添加touches属性。比如我们有Post和Comment两个关联模型<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Comment extends Model{ /** * 要更新的所有关联表 * * @var array / protected $touches = [‘post’]; /* * Get the post that the comment belongs to. */ public function post() { return $this->belongsTo(‘App\Post’); }}2. 懒加载指定字段$posts = App\Post::with(‘comment:id,name’)->get();3. 跳转指定控制器并附带参数return redirect()->action(‘SomeController@method’, [‘param’ => $value]);4. 关联时使用withDefault()在调用关联时,如果另一个模型不存在,系统会抛出一个致命错误,例如 $comment->post->title,那么我们就需要使用withDefault()…public function post(){ return $this->belongsTo(App\Post::class)->withDefault();}5. 两层循环中使用$loop在blade的foreach中,如果你想获取外层循环的变量@foreach ($users as $user) @foreach ($user->posts as $post) @if ($loop->parent->first) This is first iteration of the parent loop. @endif @endforeach @endforeach6. 浏览邮件而不发送如果你使用的是mailables来发送邮件,你可以只展示而不发送邮件Route::get(’/mailable’, function () { $invoice = App\Invoice::find(1); return new App\Mail\InvoicePaid($invoice);});7. 通过关联查询记录在hasMany关联关系中,你可以查询出关联记录必须大于5的记录$posts = Post::has(‘comment’, ‘>’, 5)->get();8. 软删除查看包含软删除的记录$posts = Post::withTrashed()->get();查看仅被软删除的记录$posts = Post::onlyTrashed()->get();恢复软删除的模型Post::withTrashed()->restore();9. Eloquent时间方法$posts = Post::whereDate(‘created_at’, ‘2018-01-31’)->get(); $posts = Post::whereMonth(‘created_at’, ‘12’)->get(); $posts = Post::whereDay(‘created_at’, ‘31’)->get(); $posts = Post::whereYear(‘created_at’, date(‘Y’))->get(); $posts = Post::whereTime(‘created_at’, ‘=’, ‘14:13:58’)->get();

April 14, 2019 · 1 min · jiezi

Laravel 框架 Model 对象转 json 字符串丢失更新

场景还原UserModelclass UserModel extends Model { public function role() { return $this->belognsTo(RoleModel::class , ‘role_id’ , ‘id’); }}出错的程序$user = UserModel::with(‘role’)->find(1);// $user->role 是一个 RoleModel// 更新 role 属性$user->role = ’test’;// 正确输出 testvar_dump($user->role);// 但是!!转换成 json 字符串后// 你会发现,role 居然还是个模型!!// 并不是你后面设置成的 test !// 怪胎,丢失更新了?Laravel Bug ??// 实际上不是!请看下属描述var_dump(json_encode($user));原理概述Laravel 的 Illuminate\Database\Eloquent\Model 实现了 JsonSerializable 接口,所以在调用 json_encode 进行序列化时,会调用 Model::jsonSerialize 方法,他这个方法返回的数据是:array_merge($attribute , $relation);实际上你通过:$model->name = ‘grayVTouch’;这种方式附加的新属性,Laravel 通过 __set 魔术方法重载,将其添加到 attribute 数组中,你是无法更改 relation 数组的!而通过 模型关联 你却可以为 relation 数组新增单元!看到上面的数组合并方式,可以知道 relation 会覆盖掉 attribute 中的同名属性!!因而要特别注意:如果 relation 中有和 attribute 中同名的属性,请修改 relation 关联名称!如果不想修改 relation 名称,坚持前者覆盖后者,请:// 保存值$attr = $model->attr;// 删除属性:attribute / relation 中的属性(Laravel 内部调用 __unset 魔术方法)unset($model->attr)// 重新设置值,仅设置到 attribute 数组// relation 并不会被设置$model->attr = $model;综合评价Laravel 由于将模型属性拆分成两个数组,而他们实际上又同属于一个对象!所以如果存在同名属性,必然会产生 谁覆盖谁 的问题,attribute 一开始就是对应数据库表中的字段的,而 relation 是后面程序附加的,为了不丢失更新,后者覆盖前者,非常正确。虽然在使用过程中应该小心避免 relation 和 attribute 撞上同名属性,但偶尔还是会碰到的~,这个还是稍微注意下就好,这并非 Bug,而是在当前的程序处理方式下必然会产生的一个正常现象。 ...

March 31, 2019 · 1 min · jiezi

Eloquent: 修改器

感觉好长时间没写东西了,一方面主要是自己的角色发生了变化,每天要面对各种各样的事情和突发事件,不能再有一个完整的长时间让自己静下来写代码,或者写文章。另一方面现在公司技术栈不再停留在只有 Laravel + VUE 了,我们还有小程序、APP 等开发,所以我关注的东西也就多了。接下来我还是会继续持续「高产」,把写技术文章当作一个习惯,坚持下去。好了,废话不多说,今天来说一说「Eloquent: 修改器」。一直想好好研究下 Eloquent。但苦于 Eloquent 有太多可研究的,无法找到一个切入点。前两天看一同事好像对这个「Eloquent: 修改器」了解不多,所以今天就拿它作为入口,扒一扒其实现源代码。首先还是拿一个 Demo 为例:Demo<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Carbon\Carbon;class Baby extends Model{ protected $table = ‘baby’; protected $appends = [‘age’]; public function getAgeAttribute() { $date = new Carbon($this->birthday); return Carbon::now()->diffInYears($date); }}这个代码比较简单,就是通过已有属性 birthday,计算 Baby 几岁了,得到 age 属性。前端就可以直接拿到结果:return $baby->age;同样的,还有 setXxxAttribute 方法来定义一个修改器。源代码读代码还是从使用入手,如上通过 $baby->age 调用 age 属性,这个属性没在类中定义,所以只能通过 PHP 的魔术方法 __get() 调用了。我们看看 Model 类的 __get() 方法:/** * Dynamically retrieve attributes on the model. * * @param string $key * @return mixed /public function __get($key){ return $this->getAttribute($key);}好了,我们开始解读源代码了:/* * Get an attribute from the model. * * @param string $key * @return mixed /public function getAttribute($key){ if (! $key) { return; } // If the attribute exists in the attribute array or has a “get” mutator we will // get the attribute’s value. Otherwise, we will proceed as if the developers // are asking for a relationship’s value. This covers both types of values. if (array_key_exists($key, $this->attributes) || $this->hasGetMutator($key)) { return $this->getAttributeValue($key); } …}重点自然就在第二个 if 上,主要判断 attributes 数组中是否包含该属性,如果没有,则会执行函数 $this->hasGetMutator($key):/* * Determine if a get mutator exists for an attribute. * * @param string $key * @return bool /public function hasGetMutator($key){ return method_exists($this, ‘get’.Str::studly($key).‘Attribute’);}这就对上了我们的 Demo 中自定义的函数 getAgeAttribute(),也就返回 true 了。接下来就是执行函数 $this->getAttributeValue($key),进而执行函数:return $this->mutateAttribute($key, $value);/* * Get the value of an attribute using its mutator. * * @param string $key * @param mixed $value * @return mixed */protected function mutateAttribute($key, $value){ return $this->{‘get’.Str::studly($key).‘Attribute’}($value);}好了,到此我们基本就知道了获取自定义 Attribute 的流程了。相信解析 set XxxAttribute 也是很简单的。总结好长时间没写东西了,先从最简单的入手,练练手。解析 Eloquent 需要费很多脑细胞,接下来的一段时间我会围绕着这个主题好好研究下去,尽可能的全部解读一遍::.|____Capsule| |____Manager.php|____composer.json|____Concerns| |____BuildsQueries.php| |____ManagesTransactions.php|____Connection.php|____ConnectionInterface.php|____ConnectionResolver.php|____ConnectionResolverInterface.php|____Connectors| |____ConnectionFactory.php| |____Connector.php| |____ConnectorInterface.php| |____MySqlConnector.php| |____PostgresConnector.php| |____SQLiteConnector.php| |____SqlServerConnector.php|____Console| |____Factories| | |____FactoryMakeCommand.php| | |____stubs| | | |____factory.stub| |____Migrations| | |____BaseCommand.php| | |____FreshCommand.php| | |____InstallCommand.php| | |____MigrateCommand.php| | |____MigrateMakeCommand.php| | |____RefreshCommand.php| | |____ResetCommand.php| | |____RollbackCommand.php| | |____StatusCommand.php| |____Seeds| | |____SeedCommand.php| | |____SeederMakeCommand.php| | |____stubs| | | |____seeder.stub|____DatabaseManager.php|____DatabaseServiceProvider.php|____DetectsDeadlocks.php|____DetectsLostConnections.php|____Eloquent| |____Builder.php| |____Collection.php| |____Concerns| | |____GuardsAttributes.php| | |____HasAttributes.php| | |____HasEvents.php| | |____HasGlobalScopes.php| | |____HasRelationships.php| | |____HasTimestamps.php| | |____HidesAttributes.php| | |____QueriesRelationships.php| |____Factory.php| |____FactoryBuilder.php| |____JsonEncodingException.php| |____MassAssignmentException.php| |____Model.php| |____ModelNotFoundException.php| |____QueueEntityResolver.php| |____RelationNotFoundException.php| |____Relations| | |____BelongsTo.php| | |____BelongsToMany.php| | |____Concerns| | | |____InteractsWithPivotTable.php| | | |____SupportsDefaultModels.php| | |____HasMany.php| | |____HasManyThrough.php| | |____HasOne.php| | |____HasOneOrMany.php| | |____MorphMany.php| | |____MorphOne.php| | |____MorphOneOrMany.php| | |____MorphPivot.php| | |____MorphTo.php| | |____MorphToMany.php| | |____Pivot.php| | |____Relation.php| |____Scope.php| |____SoftDeletes.php| |____SoftDeletingScope.php|____Events| |____ConnectionEvent.php| |____QueryExecuted.php| |____StatementPrepared.php| |____TransactionBeginning.php| |____TransactionCommitted.php| |____TransactionRolledBack.php|____Grammar.php|____Migrations| |____DatabaseMigrationRepository.php| |____Migration.php| |____MigrationCreator.php| |____MigrationRepositoryInterface.php| |____Migrator.php| |____stubs| | |____blank.stub| | |____create.stub| | |____update.stub|____MigrationServiceProvider.php|____MySqlConnection.php|____PostgresConnection.php|____Query| |____Builder.php| |____Expression.php| |____Grammars| | |____Grammar.php| | |____MySqlGrammar.php| | |____PostgresGrammar.php| | |____SQLiteGrammar.php| | |____SqlServerGrammar.php| |____JoinClause.php| |____JsonExpression.php| |____Processors| | |____MySqlProcessor.php| | |____PostgresProcessor.php| | |____Processor.php| | |____SQLiteProcessor.php| | |____SqlServerProcessor.php|____QueryException.php|____README.md|____Schema| |____Blueprint.php| |____Builder.php| |____Grammars| | |____ChangeColumn.php| | |____Grammar.php| | |____MySqlGrammar.php| | |____PostgresGrammar.php| | |____RenameColumn.php| | |____SQLiteGrammar.php| | |____SqlServerGrammar.php| |____MySqlBuilder.php| |____PostgresBuilder.php| |____SQLiteBuilder.php| |____SqlServerBuilder.php|____Seeder.php参考Eloquent: 修改器 https://laravel-china.org/docs/laravel/5.7/eloquent-mutators/2297__get()使用说明 http://php.net/manual/zh/language.oop5.overloading.php#object.get未完待续 ...

January 5, 2019 · 2 min · jiezi