我有一个带有这3个型号的Rails应用程序 - RentingUnit,Tenant&预订。
租户可以通过填写这些字段的新预订表格来预订租赁单位 - renting_unit_id,tenant_id,start_date,end_date。
start_date& end_date一起形成了renting_unit预订的持续时间。
有了这个,我想确保在一个与已经预订的任何持续时间重叠的期限内不能预订renting_unit。 (如果重要的话,我正在使用PostgreSQL数据库。)
我遇到了模型级验证的相关答案,但我也希望在数据库级别强制执行唯一性,以便考虑可能的竞争条件。
我该如何实施呢?
答案 0 :(得分:1)
在数据库中执行此类操作确实是一个明智的想法。幸运的是,PostgreSQL使这很容易。我不知道在rails中是否有内置支持,如果不是你想要运行一些自定义SQL。
CREATE TABLE booking (tenant_id int, unit_id int, start_date date, end_date date);
-- This is the constraint that prevents overlapping bookings
ALTER TABLE booking ADD constraint no_overlap
EXCLUDE USING gist (
unit_id WITH =,
daterange(start_date, end_date, '[]') WITH &&
);
-- These two abut, so that's fine
INSERT INTO booking VALUES (101, 1, '2015-01-01', '2015-01-31');
INSERT INTO booking VALUES (102, 1, '2015-02-01', '2015-02-31');
-- This one overlaps the second one, so it should fail
INSERT INTO booking VALUES (103, 1, '2015-02-01', '2015-02-01');
ERROR: conflicting key value violates exclusion constraint "no_overlap"
DETAIL: ...
注意事项。
btree_gist
扩展名以支持相等性检查详情和示例一如既往地在PostgreSQL Documentation。
中答案 1 :(得分:0)
我有一个类似的问题,上面的答案对我不起作用。
以下内容确实存在:
execute <<~SQL
ALTER TABLE booking
ADD CONSTRAINT unique_time_range_per_unit_id
EXCLUDE USING GIST (
(unit_id::text) WITH =,
tsrange(start_date, end_data) WITH &&
);
SQL
在Postgres 9.6上测试