ruby-on-rails – 当验证在另一个表上有条件时,数据库中的唯一性验证

ruby-on-rails – 当验证在另一个表上有条件时,数据库中的唯一性验证,第1张

概述我在 Uniqueness validation in database when validation has a condition问了一个类似的问题,但是我的要求发生了变化,因此这个问题. 当有多个进程时,在Rails中使用唯一性验证是不安全的,除非在数据库上也强制执行约束(在我的例子中是PostgreSQL数据库,所以参见http://robots.thoughtbot.com/the-p 我在 Uniqueness validation in database when validation has a condition问了一个类似的问题,但是我的要求发生了变化,因此这个问题.

当有多个进程时,在Rails中使用唯一性验证是不安全的,除非在数据库上也强制执行约束(在我的例子中是Postgresql数据库,所以参见http://robots.thoughtbot.com/the-perils-of-uniqueness-validations).

在我的例子中,唯一性验证是有条件的:只有在另一个模型上的另一个属性变为真时才应该强制执行.所以我有

class Parent < ActiveRecord::Base  # attribute is_publishedendclass Child < ActiveRecord::Base  belongs_to :parent  valIDates_uniqueness_of :text,if: :parent_is_published?  def parent_is_published?    self.parent.is_published  endend

所以模型Child有两个属性:parent_ID(与Parent关联)和text(文本属性).模型Parent有一个属性:is_published(布尔值).如果其parent.is_published为true,则所有类型为Child的模型的文本应该是唯一的.

使用http://robots.thoughtbot.com/the-perils-of-uniqueness-validations中建议的唯一索引太过限制,因为无论is_published的值如何,它都会强制执行约束.

是否有人知道Postgresql数据库上依赖于另一个表的“条件”索引? Uniqueness validation in database when validation has a condition的解决方案是您的条件取决于同一个表中的属性.还是另一种解决方法?

解决方法 不幸的是,没有像 your previous question那样简单和干净的解决方案.

这应该做的工作:

>将一个冗余标志is_published添加到Child表中

ALTER table child ADD column is_published boolean NOT NulL;

在插入时将其设置为DEFAulT FALSE或您在父列中通常拥有的任何内容.
它必须是NOT NulL才能避免使用NulL值的漏洞和外键中的默认MATCH SIMPLE行为:
Two-column foreign key constraint only when third column is NOT NULL
>在父级上添加(看似毫无意义的)唯一约束(parent_ID,is_published)

ALTER table parent ADD CONSTRAINT parent_fk_uniUNIQUE (parent_ID,is_published);

由于parent_ID是主键,因此组合在任何一种方式都是唯一的.但这是以下fk约束所必需的.
>不使用简单的foreign key constraint引用父(parent_ID),而是使用ON UPDATE CASCADE在(parent_ID,is_published)上创建多列外键.
这样,child.is_published的状态由系统自动维护和强制执行,并且比使用自定义触发器实现的更可靠:

ALTER table childADD CONSTRAINT child_special_fkey FOREIGN KEY (parent_ID,is_published)REFERENCES parent (parent_ID,is_published) ON UPDATE CASCADE;

>然后像上一个答案一样添加partial UNIQUE index.

CREATE UNIQUE INDEX child_txt_is_published_IDx ON child (text)WHERE is_published;

当然,在子表中插入行时,您必须立即使用parent.is_published的当前状态.但重点是:强制执行参照完整性.

完整的架构

或者,不是调整现有的架构,而是完整的布局:

CREATE table parent(    parent_ID serial PRIMARY KEY,is_published bool NOT NulL DEFAulT FALSE--,more columns ...,UNIQUE (parent_ID,is_published)   -- required for fk);CREATE table child (    child_ID serial PRIMARY KEY,parent_ID integer NOT NulL,is_published bool NOT NulL DEFAulT FALSE,txt text,FOREIGN KEY (parent_ID,is_published)      REFERENCES parent (parent_ID,is_published) ON UPDATE CASCADE);CREATE UNIQUE INDEX child_txt_is_published_IDx ON child (text)WHERE is_published;
总结

以上是内存溢出为你收集整理的ruby-on-rails – 当验证在另一个表上有条件时,数据库中的唯一性验证全部内容,希望文章能够帮你解决ruby-on-rails – 当验证在另一个表上有条件时,数据库中的唯一性验证所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1291085.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)

保存