为什么 php 的框架(Laravel、ThinkPHP)都不是在模型处统一定义数据库字段? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gamexg
V2EX    PHP

为什么 php 的框架(Laravel、ThinkPHP)都不是在模型处统一定义数据库字段?

  •  
  •   gamexg 2016 年 4 月 10 日 5677 次点击
    这是一个创建于 3580 天前的主题,其中的信息可能已经有所发展或是发生改变。

    原来用 python+django ,现在正在学习 php+Laravel 。

    一个地方想不明白, Laravel 为什么不像 django 一样统一在模型处定义数据库结构,而自动生成迁移脚本?

    目前 Laravel 需要手写移及撤销迁移的变更。多次迁移后,想知道当前数据库结构只能查看多次的迁移记录或者去数据库查看当前的数据库结构了。如果将字段定义放到模型里面能清楚知道当前代码需要的数据库结构了,迁移及撤销迁移脚本是能自动生成的。

    目前外键关系即需要在迁移脚本里面指定,还需要在模型里面指定,而且模型里面还需要指定两次,很奇怪的做法...

    ThinkPHP 和 Laravel 都是一样的做法,在模型里面定义字段是不是有什么坑?如果没有坑的话 Laravel 有没有计划将字段定义移动到模型里面?是不是已经有开源插件实现了自动生成迁移了?

    第 1 条附言    2016 年 4 月 10 日
    主要是觉得麻烦,一个外键变更需要分别在迁移、撤销迁移、两个模型处做 4 次修改...
    想问一下是不是已经有现存的插件可以解决这个问题。

    Laravel 在哪里提 issue ?很奇怪 github 未提供 issue 功能...
    第 2 条附言    2016 年 4 月 10 日
    好吧,我说一下希望达到的效果:

    1.再增加一个新的模型类型,这个新的模型定义里面需要写上这个模型包含的字段(数据库结构),每个字段的类型,是否建立索引等内容。

    增加一个命令,运行后会自动的根据新的模型生成原来的模型(包括外键之类的东西)及迁移脚本。

    生成原来的模型没什么麻烦。

    主要是生成迁移脚本麻烦些,如果不考虑导入之前的迁移脚本,那么可以完全仿 django 来实现,保存每次的变更历史,然后每次生成迁移脚本时读取之前的变更历史来获得之前的数据库结构,和当前的数据库模型作比较即可获得模型的变更,根据变更生成迁移脚本即可。

    当然实际上肯定会碰到一些坑。而且 Laravel 本身迁移功能已经实现了多种数据库的底层支持,应该不用再去适配各种数据库了。
    39 条回复    2016-04-12 00:08:37 +08:00
    chareice
        1
    chareice  
       2016 年 4 月 10 日
    Laravel 实现的是 Active record pattern 。
    gamexg
        2
    gamexg  
    OP
       2016 年 4 月 10 日
    >一个地方想不明白, Laravel 为什么不像 django 一样统一在模型处定义数据库结构,而自动生成迁移脚本?
    更正
    一个地方想不明白, Laravel 为什么不像 django 一样统一在模型处定义数据库结构,自动生成迁移脚本?

    @chareice 我之前说的不太明白。主要意思是为什么是手工写迁移、撤销迁移代码,手工写外键查询方法(而且两个相关表都需要分别写一个方法),运行时生成当前模型,代码里面没有当前数据库结构,想看当前的数据库结构只能去数据库查看。

    而不是手工定义模型字段,自动生成迁移、外键查询方法,代码内可以统一的管理当前的数据库结构呢?至少我感觉统一管理模型字段更好些。
    tabris17
        3
    tabris17  
       2016 年 4 月 10 日
    反正我设计系统都是数据库结构驱动的,先设计表结构在写模型,反过来不习惯
    whatisnew
        4
    whatisnew  
       2016 年 4 月 10 日
    migration 是个优点,多个平台的时候,数据库结构发生变化时, git pull 然后 auto migration 就好了,秒杀鸡
    whatisnew
        5
    whatisnew  
       2016 年 4 月 10 日
    错了。。。是多人开发时
    chloerei
        6
    chloerei  
       2016 年 4 月 10 日
    自动生成迁移是怎么处理数据迁移的?
    overtrue
        7
    overtrue  
       2016 年 4 月 10 日
    php 语法的原因,如果说在模型里定义了字段属性,那么 ORM 的一些特性就无法实现了,比如 getXXXAttribute/setXXXAttribute ,文档译作“属性读取器与修改器”,还有一些其它特性都是依赖于 php 的魔术方法实现的。所以这应该是语言层面决定的吧。
    jhdxr
        8
    jhdxr  
       2016 年 4 月 10 日
    @gamexg migration 你可以当做是数据库的版本控制。自动生成的迁移在表结构发生变化时能够处理所有情况吗?
    realpg
        9
    realpg  
    PRO
       2016 年 4 月 10 日
    什么都得像 django ?或者说什么框架都得像你觉得好的语言框架?不是人参攻击,我觉得是病得治
    gamexg
        10
    gamexg  
    OP
       2016 年 4 月 10 日
    @whatisnew 数据库结构直接保存到模型里面, pull 后不需要 auto migration ,检出代码后直接看模型代码,里面就是代码当前版本的数据库结构。不需要手写迁移脚本,修改模型后直接执行 manage.py makemigrations app 会自动根据模型字段的变化自动生成迁移脚本。提交代码时同时将迁移脚本一起提交,部署时和现在一样执行迁移脚本即可完成数据迁移。

    @chareice django 模型里面包含了字段定义,修改了字段定义后执行 manage.py makemigrations app 会自动生成迁移脚本。没看代码,猜测是比较将当前模型字段和迁移脚本比较,找出变更后根据变更生成迁移脚本。提交代码时同时将模型字段和迁移脚本一起提交,实际部署时和 Laravel 一样需要执行迁移命令。

    主要好处是打开模型代码就能看到代码当前版本的数据库结构,而不需要在开发环境下执行数据库迁移,然后再到数据库查看当前代码的数据库结构。
    而且外键关联也可以根据模型字段自动生成,不需要在迁移里面写一份,在模型里面再写一份。

    我主要是想问一下是不是已经有第三方实现了?
    还没开始写项目,看 Laravel 文档就觉得麻烦,一个外键变更分别需要在迁移、撤销迁移、两个模型处做 4 次修改...
    gamexg
        11
    gamexg  
    OP
       2016 年 4 月 10 日
    @realpg 主要是觉得麻烦,一个外键变更需要分别在迁移、撤销迁移、两个模型处做 4 次修改... 如果能只写一次自动生成 4 处不方便?

    @jhdxr 目前没发现不能处理的情况,添加、编辑、删除字段都能正常识别。有些破坏性迁移会给出提示,例如将允许 null 的字段修改为不允许 null ,并且没有设置默认值,生成迁移脚本时会给出多个选择。

    @overtrue 有一个简单的实现方法,现存的模型、迁移都不动,直接另外增加一个新的模型,在新模型里面保存字段,每次提交代码时运行命令自动根据新模型生成原来的模型及迁移代码。也就是替换掉 php artisan make:migration 命令。
    audi
        12
    audi  
       2016 年 4 月 10 日 via iPhone
    你可以看看 symfony 嘛
    chareice
        13
    chareice  
       2016 年 4 月 10 日
    @gamexg 原因就是数据库版本控制
    chareice
        14
    chareice  
       2016 年 4 月 10 日
    @gamexg 在 Rails 中有一个 schema.rb 文件,会自动记录当前数据库版本和结构, Laravel 好像并没有这个,所以在 Laravel 中要观察数据库的结构,还是得到数据库里看。。
    darasion
        15
    darasion  
       2016 年 4 月 10 日
    然并卵。
    很多实际需求的变化和扭曲使得你根本用不到如此多高大上的特性。
    Magician
        16
    Magician  
       2016 年 4 月 10 日 via iPhone
    Laravel 怪我咯。
    msg7086
        17
    msg7086  
       2016 年 4 月 10 日
    如果两个 PHP 系统要访问同一个数据库或者数据表怎么办?你迁移到底跑哪边的。
    PS: 你要 DRY 你得试试原厂 Ruby on Rails 。别家怎么说都是移植,把一个框架从高灵活性语言移植到低灵活性语言,总会丢掉一些灵活性的。
    realpg
        18
    realpg  
    PRO
       2016 年 4 月 10 日
    @gamexg
    那我给你还原一个最基本的应用场景你告诉我怎么做。
    我这有一个公共数据库,有三十多个 PHP WEB 项目使用,这个库的结构和迁移在哪里定义?
    wanghanlin
        19
    wanghanlin  
       2016 年 4 月 10 日   1
    Laravel 提 issue 去 laravel/framework ,不在 laravel/laravel
    gamexg
        20
    gamexg  
    OP
       2016 年 4 月 10 日
    msg7086 多个 php 系统之类的不是主要问题,这种情况关闭一个系统相关表的迁移即可。
    迁移功能是本来就有的,我只是希望能自动生成迁移脚本。 刚刚看了一下 Ruby on Rails ,每次迁移会将数据库最新结构保存到 db/schema.rb ,能清楚知道当前版本代码的数据库结构。而 Laravel 想知道当前代码的数据库结构需要应用所有迁移后再到数据库查看结构,感觉好坑啊...

    我新学 Laravel ,来这里问这个问题是想看看是不是已经有解决方案了。
    xujif
        21
    xujif  
       2016 年 4 月 10 日
    @gamexg 从 java 转过来的吧,刚开始我也这么想,不过 migration 的作用不是模型,而是迁移,迭代开发的时候,更改数据库特别好用。可以方便的 migrate or rollback ,这是模型与数据库对比做不到的。
    @msg7086 多个系统访问同一个数据库本来就不是好事, migration 不是 orm 如果使用 migrateion 只要在一个项目利用就好了。
    wanghanlin
        22
    wanghanlin  
       2016 年 4 月 10 日
    @gamexg 不是所有数据库都有对应模型的,也不是所有模型都有一个数据库, Laravel 可以处理多个模型对应同一个表。
    xujif
        23
    xujif  
       2016 年 4 月 10 日
    @gamexg 另外 laravel 没有约定模型目录,只要符合 autoload 就可以使用模型,原则上 laravel 并不知道你有多少模型,放在哪里,所以没有第三方的库帮你生成模型文件。
    php 是不能申明成员类型,所以 eloquent 不知道 relation 类型,也不能自动帮你生成外键。
    xuwenmang
        24
    xuwenmang  
       2016 年 4 月 10 日
    Migrations 用 Schema 类来定义、管理数据表的版本。
    Eloquent ORM 使用类来操作表,传说中的增删改查。


    两个不一样的事儿,搞在一起干嘛?
    gamexg
        25
    gamexg  
    OP
       2016 年 4 月 10 日
    @realpg 共用的表当然只有一个所有者开启迁移(也就一个选项的事),手写迁移脚本的时候也不会在多个项目里面都写迁移脚本啊。数据结构也一样,原来就也需要每个项目里面都写模型的外键关联,原来多个项目共享模型的外键关联现在一样共享。
    gamexg
        26
    gamexg  
    OP
       2016 年 4 月 10 日
    @xujif 是从 python +django 转过来的,原来修改了模型字段,运行一下命令会自动根据当前模型字段定义及之前的迁移脚本生成这次修改的迁移脚本,外键关联之类的更是自动生成的。现在做个修改还需要自己写迁移脚本,写外键关联,好麻烦啊。

    @xuwenmang 想偷懒啊,搞在一起我只用写一遍数据库定义,迁移、外键之类的东西能自动生成当然更省事啊。
    xujif
        27
    xujif  
       2016 年 4 月 10 日
    @gamexg php 应该没办法做到 code first ,或者说 laravel 没办法做到(因为没有约定 model 目录),忍吧。
    不过 migration 确实不是用来做这个的。 migration 的好处是强制程序员声明数据库更改,可以回溯数据库修改。协作开发的时候如果涉及数据库修改会很方便,出错了也可以回滚。
    realpg
        28
    realpg  
    PRO
       2016 年 4 月 10 日   1
    @gamexg
    建议去大厂核心数据看看。非要说 PHP 的话,有代表性的比如鹅厂的 BQQ 相关,数据库结构,设计,查询审计都是 DBA 的活,程序层可以访问完整结构去查询,但是每个查询都要审计。
    很多业务,数据库是亘古不变就存在的,而 webapp 则是满地跑。

    我并不支持 php 的这种类 ror 设计,我觉得 django 这种方便,但是什么都要设计成这种就有点强制洗脑了。
    ichou
        29
    ichou  
       2016 年 4 月 10 日
    也许你可以试一下 mongodb ,这样你就没有 migration 的困扰了
    chac88
        30
    chac88  
       2016 年 4 月 10 日
    @xujif
    强制程序员声明数据库更改

    这个有点牵强吧,还不是有人直接 navicat 改
    mcfog
        31
    mcfog  
       2016 年 4 月 10 日
    竟然没人提 doctrine
    Chrics
        32
    Chrics  
       2016 年 4 月 10 日
    因为自由
    neoblackcap
        33
    neoblackcap  
       2016 年 4 月 10 日
    @chloerei 明明你这么熟 RoR 你就不要这样子嘛,楼主的意思就是生成 migration 文件的意思,这个迁移文件当然只是一个手脚架,不含数据迁移的过程嘛。
    msg7086
        34
    msg7086  
       2016 年 4 月 11 日
    @neoblackcap migration 也可以迁移数据的啊。

    @ty0716 Rails 下几乎没有人会直接改数据库结构。
    xujif
        35
    xujif  
       2016 年 4 月 11 日
    @ty0716 这个初衷就是开发自建本地数据库,而不是大家连一个公共数据库。测试的时候重新 migration and seed 如果直接修改本地数据库,提交测试上去,如果数据库不一致,则测试必然失败,不允许发布。
    overtrue
        36
    overtrue  
       2016 年 4 月 11 日
    @gamexg 对,比如新增 Entity 来做字段映射, Model 就是现有的 Model 。 也有人这么玩的。哈哈
    gamexg
        37
    gamexg  
    OP
       2016 年 4 月 11 日
    @overtrue 有现成的开源实现吗?有的话就方便多了。
    neoblackcap
        38
    neoblackcap  
       2016 年 4 月 11 日
    @msg7086 但题主明显就不是想要手写的 mirgation 嘛,仅机器生成的又不可能做到数据迁移嘛。
    jhdxr
        39
    jhdxr  
       2016 年 4 月 12 日   1
    @gamexg 有的,上面有人提到了,叫 doctrine 。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5530 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 51ms UTC 06:43 PVG 14:43 LAX 22:43 JFK 01:43
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86