我们团队使用 ORM 写了两个例子, 争论这两个例子的优缺点. 麻烦帮忙分析一下.
表结构: user: [ id, ]
car: [ id, user_id, car_status, ]
Laravel ORM 代码:
<?php
class User extends \Illuminate\Database\Eloquent\Model
{
// 例子 1: 将取用户所有车辆的方法写在 User 中, user ID 参数使用$this->id
// 例子 1 的理由是: 因为要取得用户的所属车辆, 出发点是 User 对象所以方法应该写在 User 中, 这样会更加面向对象.
public function myCars()
{
return Car::where(['user_id' => $this->id, 'car_status' => 1])->get();
}
}
class Car extends \Illuminate\Database\Eloquent\Model
{
// 例子 2: 将取用户所有车辆的方法写在 Car 中, user ID 参数使用通过方法传递进来
// 例子 2 的理由是: 因为所查询的是 Car 表, user ID 应该作为 Car 的一个属性传递给 Car.list 方法,而且$moreCondition 可以日后增加更多筛选条件复用性好.
public function list(int $userID, $moreCondition...)
{
return $this->where(['user_id' => $userID, $moreCondition...])->get();
}
}
例子 1: 将取用户所有车辆的方法写在 User 中, user ID 参数使用$this->id 例子 1 的理由是: 因为要取得用户的所属车辆, 出发点是 User 对象所以方法应该写在 User 中, 这样会更加面向对象.
例子 2: 将取用户所有车辆的方法写在 Car 中, user ID 参数使用通过方法传递进来 例子 2 的理由是: 因为所查询的是 Car 表, user ID 应该作为 Car 的一个属性传递给 Car.list 方法,而且$moreCondition 可以日后增加更多筛选条件复用性好.
1
HanSonJ 2016-08-12 08:54:19 +08:00
我会写到一个 service 上而不是 model 上。。。
|
2
chenset OP @HanSonJ 哎呀, 不要歪楼拉. 一个方法也写 server 吗 ? 我们其实也有 repo. 但是只是想讨论这个例子中的问题而已.
|
3
lxrmido 2016-08-12 08:58:30 +08:00
其实哪怕不是 ORM ,我也经常遇到这类问题:
“获取某个用户组下的用户列表” 该写在 User 模块里还是 UserGroup 模块里呢…… |
4
justfindu 2016-08-12 09:00:07 +08:00
不用 belongs 或者 hasMany 进行关联么~
|
5
hisway 2016-08-12 09:00:20 +08:00
$this->hasMany(Car)
|
6
keikeizhang 2016-08-12 09:02:50 +08:00
class PictureController extends Controller
{ /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index(Request $req) { $user = $req->user(); $dealer = $user->dealer; $picture = Picture::orderBy('id','desc')->where('dealer','=',$dealer)->get(); return view('picture.index', compact('picture')); } } 取出一个用户拥有的所有图片... |
7
phpcxy 2016-08-12 09:03:01 +08:00
第一个查询出 $user 后,再$user->myCars()就能取得数据啦。
|
9
chenset OP 能实现的方式很多拉 . 但是主要想问的还是这个方法应该写在 User 中还是 Car 中.
|
11
inmyfree 2016-08-12 09:10:04 +08:00
写到 Car 里面,然后在 User 添加一个 carList 方法,里面调用 Car.list,完事
|
12
inmyfree 2016-08-12 09:10:33 +08:00
ps : android 写多了看出 OOM 了,哎
|
13
gearh 2016-08-12 09:11:58 +08:00
没有 ORM 时写在 user 中,用 ORM 直接关联啊,关联!
|
14
freefcw 2016-08-12 09:14:20 +08:00
必须第一种撒。。第二种还自己去折腾,关键代码读起来 shi 一样不连贯
|
15
tabris17 2016-08-12 09:16:17 +08:00
写在 User 里,这是个 hasMany 的关系
|
16
sujin190 2016-08-12 09:16:24 +08:00
重点是当和用户相关的数据越来越多的时候用户 model 里岂不是越来越多方法,每个细分功能都会修改 user model ,这样不合适吧,除非所有细分功能共用,否则最好还是写到各自 model 里比较好
|
17
solaya 2016-08-12 09:22:16 +08:00 1
不是用 hsaMany belongsTo ???
|
18
jiujianlu 2016-08-12 09:23:19 +08:00
使用第一种,将来使用关联关系重构的时候,改动比较小。
|
20
freefcw 2016-08-12 09:26:22 +08:00
说错了。。。 Laravel 自带的 Relation 就是极好的,没必要这么折腾
|
22
laoyuan 2016-08-12 09:52:39 +08:00
你们团队都没有看过文档的 Tutorials 么
https://laravel.com/docs/5.2/quickstart-intermediate#eloquent-relationships class User extends Authenticatable { // Other Eloquent Properties... /** * Get all of the tasks for the user. */ public function tasks() { return $this->hasMany(Task::class); } |
23
laoyuan 2016-08-12 09:53:55 +08:00
20%的回复提到了 hasMany(),靠谱!
|
24
aggron 2016-08-12 10:02:48 +08:00
赞同 @sujin190 我觉得还是放在 Car 中合适些,系统里与 User 相关的 model 太多了,放里面只会越来越庞大,个人觉得为了“更面向对象”放里面不是个好的设计
随便选一个算是智者见智吧,可以参考下领域模型中的相关设计 http://www.oschina.net/question/98375_21638 |
25
MrJing1992 2016-08-12 10:09:15 +08:00
按业务逻辑拆分功能。
当你上 Car 这个业务时,就有了“用户所有的车”这个功能。当你要下线 Car 这个业务时,如果你还有去改 User 业务的代码那是不太合理的。 所有结论就是:这个功能属于 Car 业务,就放在 Car 业务相关的代码里面。 |
26
jinchun 2016-08-12 10:55:27 +08:00 1
model 里应该都是 hasMany 和 belongsTO 的关系。。你这代码应该是放在 repositories 里。具体看这个:
http://slashnode.com/reusable-repository-design-in-laravel/ |
27
lzsadam 2016-08-12 11:10:15 +08:00
多表查询的话我是以主表为主的
这里的主表应该是 car 话说我也会写在 service 层 |
28
chenset OP @laoyuan 你都没有看帖子吗? "不使用关联关系不手写 SQL 时, 我们团队在争论这两种写法的优劣, 想看看大家的看法."
|
29
SayHaHa 2016-08-12 11:28:33 +08:00 via Android
支持写在 User 中
|
30
Liang 2016-08-12 11:43:52 +08:00
要看是否一辆车是否属于多个人,或一个人是否拥有多辆车。
看数据表结构,应该是后者。 我习惯会把"->"当成"的"。$user->cars()会更好, User 中使用 hasMany()。 个人习惯~不代表权威 |
31
mahone3297 2016-08-12 11:49:00 +08:00
写在 User 中?那一个用户,如果有多辆车,那是 User 表中多条数据?那还叫 User 表? User 表不是一个 user 一条数据?
|
32
shuson 2016-08-12 11:50:47 +08:00
hasMany 是正解,不要 anti pattern
|
33
wanghanlin 2016-08-12 12:00:11 +08:00
还是推荐使用 relationships ,没必要这么搞,不过回到这个问题,还是放 User 里合适
|
34
assad 2016-08-12 13:47:42 +08:00
一个破 SQL ,费用要什么 HasMany ,遇到复杂设计的,奇葩需求的,统统不好使。真心不喜欢框架这种 ORM ,简单的业务还行,一遇到复杂的需求,还是直接写 SQL ,建立一个 model ,自己处理的好!
|
35
justfindu 2016-08-12 13:51:38 +08:00
按你这个设计 那就应该放第二种, 并且 user_id 不作为必要条件 这样更能复用
|
36
silov 2016-08-12 13:53:09 +08:00
hasMany 和 belongsTo 什么的可以很好的完成你的需求,尤其是配合预加载的时候。
顺便吐槽一下第一种,你在一个 Model 里面写另一个 model 的 where 条件查询,不觉得怪么? |
37
zhangchaozheng 2016-08-12 16:28:10 +08:00
孩纸们,忘掉 ORM 这种东西吧!
|
39
cxbig 2016-08-12 17:59:15 +08:00
1. 肯定会定义关联
2. User->myCars() |
40
klgd 2016-08-12 22:45:20 +08:00
如果在不使用关联关系的情况下,我选第二种,各自操作各自的表,互不干扰
当然要是用关联关系的话,那就是 User 里使用 hasMany ps :我觉得比较规范点儿的表结构是 users , cars , user_car 三个表 |
41
caola 2016-08-13 01:22:55 +08:00
表的名称应该为复数,多数情况下是加上个“ s ”, user 表名应该为 users ,这也是 laravel 默认的命名方式。
ORM 中如果不是这样复数的表,你可能要多写几个代码 -----抱歉,我并没有回答你的问题----- |
42
miaotaizi 2016-08-13 11:33:01 +08:00 via iPhone
@MrJing1992 顶
如果是我我就把这个方法写在 car 中,并且为一个静态方法. 首先你取得的是 car ,而不是 user ,这一点就应该在 car 中 . 并且你这个方法想必跟 car 实体本身没什么太大关系,那这个方法就应该是一个静态方法. 至于如何在 user 获取所有的 car ,那就是 user 如何去调用 car 类中的方法的事儿了. |
43
kzzhr 2016-08-14 09:04:11 +08:00 via Android
@assad 用 relation 在将来可以写 whereHas (a.b.c.d ),手写 SQL 不会疯?
|
45
AbrahamGreyson 2016-08-18 00:51:10 +08:00
个人觉得这和 ORM 与否没什么关系,不是 Eloquent 才会出现的疑惑,更和面向对象没关系,因为我们的开发,早已经假设一切问题都建立在 oop 之上。并不是说 this.id 就是 oop , oop 更多的是一种思考问题的方式。
我们从思考问题的方式出发。 首先还得看业务需求,如果 User 是一个模块 /领域模型 /聚集的根(主入口,唯一标识),那么它内部所维护的各个值对象理应通过 User 来拿,我们姑且以模块来称呼这个 User 的功能,如果 User 这个模块的一个重要功能是按照特定的 User 实体去获得属于他的 /关联的其它对象,我想不出为什么不直接写在 User 数据库类中,因为,特定的用户不存在的时候,与他相关的一切其它值都将失去意义。 Laravel ORM 把对象关系映射、实体、模块聚集浓缩到了一层中,直接去在 User 对象中访问模块内部的其它元素便是了。然后你可能因为测试 /关注分离 /业务和基础设施分离等原因,可能会在客户端代码和 User 对象中增加类似 Repository 、 Factory 之类的东西,这个时候 Factory 返回的将是一个 User 模块的聚集,它的根是 User 对象,它的其它元素,就是你自己维护的与 User 对象相关的其它实体。 尽管这样我也见过有人用另一种方式,也就是使用动态的数据库查询去返回对象(楼主的方法 2 ),这么做的目的是给 User 模块瘦身,但是我个人偏好第一种。第一种方式拿 User 的关联元素, 维护时可能仅仅需要修改特定类的方法,第二种则要修改分散到系统各处的条件,甚至更复杂些,有人用对象表示查询条件。 |