2012-03-06 78 views
5

我有一个租用表如下表结构:如何防止SQL中的日期重叠?

hireId int primary key 
carId int not null foreign key 
onHireDate datetime not null 
offHireDate datetime not null 

我试图编程一个多用户系统,不允许汽车重叠onhire和停租期间。我需要能够以非连续顺序添加员工。还需要允许编辑雇员。

任何方式来约束表或使用触发器等,以防止重叠?我使用实体框架,所以我将要插入到表正常,然后如果失败抛出一些例外开捕等

+3

我能想到的唯一面向数据库的解决方案是设置一个'INSTEAD OF'触发器,一个执行检查的过程。但我会避免它,并检查代码中的重叠! – vulkanino 2012-03-06 10:09:30

+0

从实体框架的角度来看,我不认为我可以在代码中轻松检查。我可以检查一点,但有两个人同时添加/编辑事件的可能性 – GraemeMiller 2012-03-06 10:17:48

+0

我认为实体框架将使数据访问更容易,而不是更难!毕竟这是一个简单的检查。并发性是一个问题,你可以通过锁定解决,如果架构允许你(网络/无状态?) – vulkanino 2012-03-06 10:27:00

回答

3

考虑这个查询:如果所有的行都满足您

SELECT * 
FROM Hire AS H1, Hire AS H2 
WHERE H1.carId = H2.carId 
AND H1.hireId < H2.hireId 
AND 
    CASE 
    WHEN H1.onHireDate > H2.onHireDate THEN H1.onHireDate 
    ELSE H2.onHireDate END 
    < 
    CASE 
    WHEN H1.offHireDate > H2.offHireDate THEN H2.offHireDate 
    ELSE H1.offHireDate END 

业务规则,则该查询将是空集(假设closed-open representation of periods即结束日期是在期间内未考虑的最早时间粒度)。

因为SQL Server does not support subqueries within CHECK constraints,把同样的逻辑触发(但不是INSTEAD OF触发,除非你能到决心重叠提供逻辑)。使用Fowler


替代查询:

SELECT * 
    FROM Hire AS H1, Hire AS H2 
WHERE H1.carId = H2.carId 
     AND H1.hireId < H2.hireId 
     AND H1.onHireDate < H2.offHireDate 
     AND H2.onHireDate < H1.offHireDate; 
+0

所以,如果重叠发生我不应该使用INSTEAD OF触发器抛出一个异常?我可以捕获异常并让用户修复它。 – GraemeMiller 2012-03-06 13:03:04

+0

@GraemeMiller:使用'AFTER'触发器。 – onedaywhen 2012-03-06 13:06:41

+0

所以我会插入项目和后触发器将回滚并提出重叠错误? – GraemeMiller 2012-03-06 13:27:41

3
CREATE TRIGGER tri_check_date_overlap ON your_table 
INSTEAD OF INSERT 
AS 
BEGIN 
    IF @@ROWCOUNT = 0 
     RETURN 

    -- check for overlaps in table 'INSERTED' 
    IF EXISTS(
     SELECT hireId FROM your_table WHERE 
      (INSERTED.onHireDate BETWEEN onHireDate AND offHireDate) OR 
      (INSERTED.offHireDate BETWEEN onHireDate AND offHireDate) 
    ) 
     BEGIN 
      -- exception? or do nothing? 
     END 
    ELSE 
     BEGIN 
     END 
END 
GO 
+0

没有测试它,我不知道检查实际上是否有效。 – vulkanino 2012-03-06 11:08:40

+0

它不检查重叠,如果两个重叠的行插入单个插入语句(既没有行的表重叠的现有行) – 2012-03-06 11:15:30

+0

@Damien_The_Unbeliever可以更正SP? – vulkanino 2012-03-06 11:17:25

0
我现在用的领域驱动设计技术

。这让我不必担心数据库触发器等问题,并保留.Net代码中的所有逻辑。答案在这里,让人们可以看到另一种选择。

我把期间集合的父母当作aggregate root,并且根有一个时间戳。聚合根是事务,分布和并发性的一致性边界(请参阅Evans - what I've learned since the blue book)。这用于检查上次向数据库确认任何更改的时间。

然后我有方法将聘用期间添加到父项。将运动添加到聚合根时,我会对重叠进行测试。例如AddHire(start,end) - 将验证这会在内存域对象上创建不重叠。

由于没有重叠,我保存更改(通过我的存储库),并检查数据库时间戳是否仍然与流程开始时相同。假设时间戳与我检索实体时的时间戳相同,则更改将持续存在,并且数据库会更新时间戳。

如果有人试图保存更改,当聚合根正在工作时,然后我会先提交或他们会。如果我首先提交时间戳不匹配,重叠检查将重新运行,以确保它们在间隔时间内未创建重叠。