我正在使用Laravel编写一个DB迁移,我想知道是否可以根据另一列的值将一列设置为不可为null。
例如:
If User.owns_cat === true
Then User.cat_name->nullable(false)
我知道我以后可以通过验证规则来处理这个问题,但我希望在DB级别有这个规则。
您真正需要的是对条件函数依赖项和关联规则的支持。
关联规则(AR(
c=>f(A(
其中c是逻辑上可确定的值,如果满足该值,则列集a将填充
A=(A1,A2,…,An(
条件函数相关性(CFD(
c=>A->B
其中c是逻辑上可确定的值,如果满足该值,则列集合a确定列集合B的值,其中
A=(A1,A2,…,An(
和
B=(B1,B2,…,Bn(
问题
RDBMS系统往往不支持开箱即用的AR或CFD,至少我上次检查时是这样。因此,由于底层系统可能不支持您需要的功能,Laravel迁移也可能无法实现这一点。
解决方案
基于应用程序代码定义模式的问题是,这项任务在技术堆栈的ORM级别上做得不太合适,因为:
- 您使用了一些只能间接影响的模式生成器
- 更复杂的问题很难通过这样的系统来解决
- 模式更改生成器可能有错误,这会不必要地给您的问题增加新的担忧级别
所以,你可以做什么:
- 您可以在应用程序级别实现一个功能,该功能检查某些条件,如果满足条件,则强制执行规则,也就是说,如果违反规则,则抛出错误或设置默认值,而如果满足规则,则调用set
- 您可以在数据库中实现一个触发器,在插入/更新之前,该触发器将检查并强制执行您需要的规则
- 架构解决方案
- 定期运行数据修复
触发器
您将创建一个触发器,该触发器将检查column2的值,如果满足条件,则检查column1是否为null。如果是这样,那么您可能会选择抛出错误或设置默认值。
优势:即使写入操作发生在应用程序之外,您的数据一致性也将得到维护。
缺点:如果规则经常更改,并且无法访问您的应用程序级资源,则很难维护。
这种方法是否适合您,取决于您的需求。
架构解决方案
所以,如果c1有某个值,那么c2是不可为null的。您可以将c1移到另一个表,并将c2设为外键。如果满足c1的条件,请确保c2是保存c1的新表的正确外键。
优势:您只使用RDBMS为您提供的现成资源
缺点:如果你的c2条件是复杂的,这种方法是反直觉的
这种方法的适用性取决于您的病情的复杂性。
定期运行数据修复
您可以允许与规则暂时不一致,并定期自动解决问题。
优点:解决方案可能是对数据库服务器的单个请求,该服务器将执行存储过程或类似操作,从而快速执行任务。
缺点:您不能依赖于您的规则在每一个记录的每一刻都得到执行。
如果你不担心你的规则被暂时违反,只要它很快得到纠正,这是适用的。
应用程序级支持
您可以实现一个具有set方法的类。该set方法将获得一个实体和一个返回布尔值的函数。如果函数返回true,则调用set。否则,抛出异常或设置默认值。