2012-03-06 10 views
5

Ho la seguente struttura della tabella per una tabella a noleggio:Come posso evitare la sovrapposizione di date in SQL?

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

sto cercando di programmare un sistema multi-utente che non consente periodo onhire e offhire per le auto a sovrapporsi. Devo essere in grado di aggiungere assunzioni in ordine non sequenziale. Inoltre, è necessario consentire la modifica delle assunzioni.

Un modo per limitare le tabelle o utilizzare i trigger ecc. Per evitare sovrapposizioni? Sto usando Entity Framework così vorrei inserire al tavolo come normale e poi se non riesce gettare un po 'un'eccezione catturabile ecc

+3

l'unica soluzione orientata al database che posso pensare è la creazione di un trigger "INSTEAD OF', una procedura che esegue il controllo. ma vorrei evitarlo e controllare la sovrapposizione di codice! – vulkanino

+0

Da un punto di vista del framework di entità non penso di poter controllare facilmente nel codice. Posso verificare a un certo punto ma c'è la possibilità che due persone aggiungano/modificino gli eventi allo stesso tempo – GraemeMiller

+0

Ho pensato che il framework delle entità avrebbe reso l'accesso ai dati più facile, non più difficile! Dopo tutto è un semplice controllo. La concorrenza è un problema, che potresti risolvere con il blocco, se l'architettura ti permette di (web/stateless?) Sito Web – vulkanino

risposta

3

Considerate questa query:

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 

Se tutte le righe si incontrano regola aziendale quindi questa query sarà il set vuoto (supponendo closed-open representation of periods cioè dove la data di fine è il primo granello di tempo che non è considerato nel periodo).

Perché SQL Server does not support subqueries within CHECK constraints, mettere la stessa logica in un trigger (ma non un INSTEAD OF grilletto, a meno che non è possibile fornire la logica per risolvere sovrapposizioni).


interrogazione alternativo utilizzando 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

Quindi non dovrei usare invece di trigger per generare un'eccezione se si verificano sovrapposizioni? Posso rilevare un'eccezione e chiedere all'utente di risolverlo. – GraemeMiller

+0

@GraemeMiller: usa un trigger 'DOPO'. – onedaywhen

+0

Quindi vorrei inserire l'elemento e il trigger successivo lo avrebbe riportato indietro e generato un errore nella sovrapposizione? – GraemeMiller

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

non l'ho testato, non so se il controllo funziona davvero. – vulkanino

+0

Non verifica la sovrapposizione se due righe sovrapposte sono inserite in una singola istruzione di inserimento (dove nessuna riga si sovrappone a una riga esistente nella tabella) –

+0

@Damien_The_Unbeliever è possibile correggere l'SP? – vulkanino

0

ora sto usando dominio guidato tecniche di progettazione. Questo mi impedisce di preoccuparmi dei trigger di database ecc. E mantiene tutta la logica all'interno del codice .Net. La risposta è qui in modo che le persone possano vedere un'alternativa.

Trattiamo il genitore dell'insieme di periodi come aggregate root e la radice ha un timestamp. La radice aggregata è un limite di coerenza per transazioni, distribuzioni e concorrenza (vedere Evans - what I've learned since the blue book). Questo è usato per controllare l'ultima volta che ogni cambiamento è stato confermato al database.

Ho quindi metodi per aggiungere i periodi di noleggio al genitore. Eseguo il test sulla sovrapposizione quando aggiungo il movimento alla radice aggregata. per esempio. AddHire(start,end) - confermerà che ciò non crea alcuna sovrapposizione sull'oggetto del dominio in memoria.

AS non esiste alcuna sovrapposizione, salvo le modifiche (tramite il mio repository) e controllo che il timestamp del database sia sempre lo stesso all'inizio del processo. Supponendo che il timestamp sia lo stesso di quando ho recuperato l'entità, le modifiche vengono mantenute e il database aggiorna il timestamp.

Se qualcun altro tenta di salvare le modifiche quando viene elaborata la radice aggregata, allora eseguirò il commit per primo o lo faranno. Se eseguo il commit prima, i timestamp non corrisponderanno e il controllo di sovrapposizione verrà eseguito di nuovo per assicurarsi che non abbiano creato una sovrapposizione nel tempo intercorrente.

Problemi correlati