Как создать столбец нулевой или не нулевой в зависимости от значения другого столбца? - PullRequest
1 голос
/ 16 апреля 2019

Я использую подход базы данных с ядром EF и пытаюсь найти чистое решение для следующей проблемы -

Рассмотрим таблицу посещаемости ученика (несущественные столбцы удалены) ниже, в которой хранится дата занятия и позволяет ученику ввести свой рейтинг класса -

create table Student (
    Id int Identity(1, 1) not null,
    ClassDate smalldatetime not null,
    ClassRatingByStudent varchar(250) not null
) 

Это веб-приложение, в котором система посещаемости школы автоматически заполняет вышеуказанную таблицу в EOD, а затем студент (скажем, через несколько дней) должен добавить оценки класса. Когда таблица заполняется системой посещаемости школы, в столбце ClassRatingByStudent ничего нет. Затем, когда студент входит в систему, он должен добавить оценку.

Как видите, ClassRatingByStudent должен быть нулевым, когда система посещаемости школы заполняет таблицу, и должен быть не нулевым, когда ученик сохраняет свои изменения. Одно очевидное решение - сделать так, чтобы столбец ClassRatingByStudent обнулялся и обрабатывал его в коде, но мне интересно, существует ли более точное решение для базы данных (или, может быть, EF) или есть какие-то рекомендации по шаблонам / архитектуре для этого типа сценариев?

Ответы [ 2 ]

4 голосов
/ 16 апреля 2019

Я не знаю, но, возможно, ограничение CHECK может помочь вам:

CREATE TABLE TestTable(
  ID int NOT NULL IDENTITY,
  RatingAllowed bit NOT NULL DEFAULT 0, -- switcher
  RatingValue varchar(250),
CONSTRAINT PK_TestTable PRIMARY KEY(ID),
CONSTRAINT CK_TestTable_RatingValue CHECK( -- constraint
                    CASE
                      WHEN RatingAllowed=0 AND RatingValue IS NULL THEN 1
                      WHEN RatingAllowed=1 AND RatingValue IS NOT NULL THEN 1
                      ELSE 0
                    END=1
                 )
)

INSERT TestTable(RatingAllowed,RatingValue)VALUES(0,NULL)
INSERT TestTable(RatingAllowed,RatingValue)VALUES(1,'AAA')

-- The INSERT statement conflicted with the CHECK constraint "CK_TestTable_RatingValue"
INSERT TestTable(RatingAllowed,RatingValue)VALUES(0,'AAA')
INSERT TestTable(RatingAllowed,RatingValue)VALUES(1,NULL)
1 голос
/ 17 апреля 2019

Я нашел вариант, как проверить, используя другую таблицу в качестве переключателя

CREATE TABLE TableA(
  ID int NOT NULL IDENTITY PRIMARY KEY,
  StudentID int NOT NULL,
  Grade int
)

CREATE TABLE TableB(
  StudentID int NOT NULL PRIMARY KEY
)
GO

-- auxiliary function
CREATE FUNCTION GradeIsAllowed(@StudentID int)
RETURNS bit
BEGIN
  DECLARE @Result bit=CASE WHEN EXISTS(SELECT * FROM TableB WHERE StudentID=@StudentID) THEN 1 ELSE 0 END
  RETURN @Result
END
GO

-- constraint to check
ALTER TABLE TableA ADD CONSTRAINT CK_TableA_Grade CHECK(
                CASE dbo.GradeIsAllowed(StudentID) -- then we can use the function here
                  WHEN 1 THEN CASE WHEN Grade IS NOT NULL THEN 1 ELSE 0 END
                  WHEN 0 THEN CASE WHEN Grade IS NULL THEN 1 ELSE 0 END
                END=1)
GO

-- Tests
INSERT TableB(StudentID)VALUES(2) -- allowed student

INSERT TableA(StudentID,Grade)VALUES(1,NULL) -- OK
INSERT TableA(StudentID,Grade)VALUES(2,5) -- OK

INSERT TableA(StudentID,Grade)VALUES(1,4) -- Error
INSERT TableA(StudentID,Grade)VALUES(2,NULL) -- Error

INSERT TableB(StudentID)VALUES(1) -- add 1

UPDATE TableA SET Grade=4 WHERE StudentID=1 -- OK
UPDATE TableA SET Grade=NULL WHERE StudentID=1 -- Error
...