ฉันได้ระบุ 3 สถานการณ์
- นักเรียนที่ไม่มีการลงทะเบียน
- นักเรียนที่มีการลงทะเบียน แต่ไม่มีเกรด
- นักเรียนที่มีการลงทะเบียนและผลการเรียน
มีทริกเกอร์ในตารางการลงทะเบียนเพื่อคำนวณเกรดเฉลี่ย หากนักเรียนมีคะแนนจะทำการอัปเดตหรือแทรกรายการลงในตารางเกรดเฉลี่ย ไม่มีเกรดไม่มีรายการตารางเกรดเฉลี่ย
ฉันสามารถลบนักเรียนที่ไม่มีการลงทะเบียน (# 1) ฉันสามารถลบนักเรียนที่มีการลงทะเบียนและผลการเรียน (# 3 ด้านบน) แต่ฉันไม่สามารถลบนักเรียนที่มีการลงทะเบียน แต่ไม่มีคะแนน (# 2) ฉันได้รับการละเมิดข้อ จำกัด ในการอ้างอิง
คำสั่ง DELETE ขัดแย้งกับข้อ จำกัด การอ้างอิง "FK_dbo.GPA_dbo.Student_StudentID" ความขัดแย้งเกิดขึ้นในฐานข้อมูล "", ตาราง "dbo.GPA", คอลัมน์ 'StudentID'
หากฉันไม่สามารถลบนักเรียนใหม่ที่ไม่มีการลงทะเบียน (และไม่มีรายการ GPA) ฉันจะเข้าใจการละเมิดข้อ จำกัด แต่ฉันสามารถลบนักเรียนคนนั้นได้ เป็นนักเรียนที่มีการลงทะเบียนและไม่มีคะแนน (และยังไม่มีรายการเกรดเฉลี่ย) ที่ฉันไม่สามารถลบได้
ฉันได้ติดตั้งทริกเกอร์ของฉันเพื่อให้สามารถไปข้างหน้า ทีนี้ถ้าคุณมีการลงทะเบียนทริกเกอร์จะแทรกคุณลงในตารางเกรดเฉลี่ยไม่ว่าจะเกิดอะไรขึ้น แต่ฉันไม่เข้าใจปัญหาพื้นฐาน คำอธิบายใด ๆ ที่จะได้รับการชื่นชมมากที่สุด
สำหรับสิ่งที่คุ้มค่า:
- Visual Studio 2013 Professional
- IIS express (ภายในถึง VS2013)
- ASP.NET Web App ที่ใช้ EntityFramework 6.1.1
- องค์กร MS SQL Server 2014
- GPA.Value เป็นโมฆะ
- Enrollment.GradeID เป็นโมฆะ
นี่เป็นตัวอย่างของฐานข้อมูล:
- แก้ไข -
ตารางทั้งหมดถูกสร้างโดย EntityFramework ฉันใช้ SQL Server Management Studio เพื่อผลิตสิ่งเหล่านี้
นี่คือคำสั่งสร้างตารางที่มีข้อ จำกัด :
GPA
โต๊ะ:
CREATE TABLE [dbo].[GPA](
[StudentID] [int] NOT NULL,
[Value] [float] NULL,
CONSTRAINT [PK_dbo.GPA] PRIMARY KEY CLUSTERED
(
[StudentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[GPA] WITH CHECK
ADD CONSTRAINT [FK_dbo.GPA_dbo.Student_StudentID]
FOREIGN KEY([StudentID])
REFERENCES [dbo].[Student] ([ID])
ALTER TABLE [dbo].[GPA]
CHECK CONSTRAINT [FK_dbo.GPA_dbo.Student_StudentID]
Enrollment
โต๊ะ:
CREATE TABLE [dbo].[Enrollment](
[EnrollmentID] [int] IDENTITY(1,1) NOT NULL,
[CourseID] [int] NOT NULL,
[StudentID] [int] NOT NULL,
[GradeID] [int] NULL,
CONSTRAINT [PK_dbo.Enrollment] PRIMARY KEY CLUSTERED
(
[EnrollmentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[Enrollment] WITH CHECK
ADD CONSTRAINT [FK_dbo.Enrollment_dbo.Course_CourseID]
FOREIGN KEY([CourseID])
REFERENCES [dbo].[Course] ([CourseID])
ON DELETE CASCADE
ALTER TABLE [dbo].[Enrollment]
CHECK CONSTRAINT [FK_dbo.Enrollment_dbo.Course_CourseID]
ALTER TABLE [dbo].[Enrollment] WITH CHECK
ADD CONSTRAINT [FK_dbo.Enrollment_dbo.Grade_GradeID]
FOREIGN KEY([GradeID])
REFERENCES [dbo].[Grade] ([GradeID])
ALTER TABLE [dbo].[Enrollment]
CHECK CONSTRAINT [FK_dbo.Enrollment_dbo.Grade_GradeID]
ALTER TABLE [dbo].[Enrollment] WITH CHECK
ADD CONSTRAINT [FK_dbo.Enrollment_dbo.Student_StudentID]
FOREIGN KEY([StudentID])
REFERENCES [dbo].[Student] ([ID])
ON DELETE CASCADE
ALTER TABLE [dbo].[Enrollment]
CHECK CONSTRAINT [FK_dbo.Enrollment_dbo.Student_StudentID]
Student
โต๊ะ:
CREATE TABLE [dbo].[Student](
[ID] [int] IDENTITY(1,1) NOT NULL,
[EnrollmentDate] [datetime] NOT NULL,
[LastName] [nvarchar](50) NOT NULL,
[FirstName] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
นี่คือทริกเกอร์ :
CREATE TRIGGER UpdateGPAFromUpdateDelete
ON Enrollment
AFTER UPDATE, DELETE AS
BEGIN
DECLARE @UpdatedStudentID AS int
SELECT @UpdatedStudentID = StudentID FROM DELETED
EXEC MergeGPA @UpdatedStudentID
END
CREATE TRIGGER UpdateGPAFromInsert
ON Enrollment
AFTER INSERT AS
--DECLARE @InsertedGradeID AS int
--SELECT @InsertedGradeID = GradeID FROM INSERTED
--IF @InsertedGradeID IS NOT NULL
BEGIN
DECLARE @InsertedStudentID AS int
SELECT @InsertedStudentID = StudentID FROM INSERTED
EXEC MergeGPA @InsertedStudentID
END
แพทช์ที่จะเดินหน้าต่อไปคือแสดงความคิดเห็นในบรรทัดเหล่านั้นในAFTER INSERT
ทริกเกอร์
นี่คือขั้นตอนการจัดเก็บ :
CREATE PROCEDURE MergeGPA @StudentID int AS
MERGE GPA AS TARGET
USING (SELECT @StudentID) as SOURCE (StudentID)
ON (TARGET.StudentID = SOURCE.StudentID)
WHEN MATCHED THEN
UPDATE
SET Value = (SELECT Value FROM GetGPA(@StudentID))
WHEN NOT MATCHED THEN
INSERT (StudentID, Value)
VALUES(SOURCE.StudentID, (SELECT Value FROM GetGPA(@StudentID)));
นี่คือฟังก์ชั่นฐานข้อมูล:
CREATE FUNCTION GetGPA (@StudentID int)
RETURNS TABLE
AS RETURN
SELECT ROUND(SUM (StudentTotal.TotalCredits) / SUM (StudentTotal.Credits), 2) Value
FROM (
SELECT
CAST(Credits as float) Credits
, CAST(SUM(Value * Credits) as float) TotalCredits
FROM
Enrollment e
JOIN Course c ON c.CourseID = e.CourseID
JOIN Grade g ON e.GradeID = g.GradeID
WHERE
e.StudentID = @StudentID AND
e.GradeID IS NOT NULL
GROUP BY
StudentID
, Value
, e.courseID
, Credits
) StudentTotal
นี่คือผลลัพธ์การดีบักจากวิธีการลบของคอนโทรลเลอร์คำสั่ง select เป็นวิธีการสอบถามว่าจะลบอะไร นักเรียนนี้มี 3 การลงทะเบียนREFERENCE
ปัญหาข้อ จำกัด เกิดขึ้นเมื่อการลงทะเบียนครั้งที่ 3 ลบ ฉันคิดว่า EF ใช้ธุรกรรมเพราะการลงทะเบียนจะไม่ถูกลบ
iisexpress.exe Information: 0 : Component:SQL Database;Method:SchoolInterceptor.ReaderExecuted;Timespan:00:00:00.0004945;Properties:
Command: SELECT
[Project2].[StudentID] AS [StudentID],
[Project2].[ID] AS [ID],
[Project2].[EnrollmentDate] AS [EnrollmentDate],
[Project2].[LastName] AS [LastName],
[Project2].[FirstName] AS [FirstName],
[Project2].[Value] AS [Value],
[Project2].[C1] AS [C1],
[Project2].[EnrollmentID] AS [EnrollmentID],
[Project2].[CourseID] AS [CourseID],
[Project2].[StudentID1] AS [StudentID1],
[Project2].[GradeID] AS [GradeID]
FROM ( SELECT
[Limit1].[ID] AS [ID],
[Limit1].[EnrollmentDate] AS [EnrollmentDate],
[Limit1].[LastName] AS [LastName],
[Limit1].[FirstName] AS [FirstName],
[Limit1].[StudentID] AS [StudentID],
[Limit1].[Value] AS [Value],
[Extent3].[EnrollmentID] AS [EnrollmentID],
[Extent3].[CourseID] AS [CourseID],
[Extent3].[StudentID] AS [StudentID1],
[Extent3].[GradeID] AS [GradeID],
CASE WHEN ([Extent3].[EnrollmentID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM (SELECT TOP (2)
[Extent1].[ID] AS [ID],
[Extent1].[EnrollmentDate] AS [EnrollmentDate],
[Extent1].[LastName] AS [LastName],
[Extent1].[FirstName] AS [FirstName],
[Extent2].[StudentID] AS [StudentID],
[Extent2].[Value] AS [Value]
FROM [dbo].[Student] AS [Extent1]
LEFT OUTER JOIN [dbo].[GPA] AS [Extent2] ON [Extent1].[ID] = [Extent2].[StudentID]
WHERE [Extent1].[ID] = @p__linq__0 ) AS [Limit1]
LEFT OUTER JOIN [dbo].[Enrollment] AS [Extent3] ON [Limit1].[ID] = [Extent3].[StudentID]
) AS [Project2]
ORDER BY [Project2].[StudentID] ASC, [Project2].[ID] ASC, [Project2].[C1] ASC:
iisexpress.exe Information: 0 : Component:SQL Database;Method:SchoolInterceptor.NonQueryExecuted;Timespan:00:00:00.0012696;Properties:
Command: DELETE [dbo].[Enrollment]
WHERE ([EnrollmentID] = @0):
iisexpress.exe Information: 0 : Component:SQL Database;Method:SchoolInterceptor.NonQueryExecuted;Timespan:00:00:00.0002634;Properties:
Command: DELETE [dbo].[Enrollment]
WHERE ([EnrollmentID] = @0):
iisexpress.exe Information: 0 : Component:SQL Database;Method:SchoolInterceptor.NonQueryExecuted;Timespan:00:00:00.0002512;Properties:
Command: DELETE [dbo].[Enrollment]
WHERE ([EnrollmentID] = @0):
iisexpress.exe Error: 0 : Error executing command: DELETE [dbo].[Student]
WHERE ([ID] = @0) Exception: System.Data.SqlClient.SqlException (0x80131904): The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.GPA_dbo.Student_StudentID". The conflict occurred in database "<databasename>", table "dbo.GPA", column 'StudentID'.
The statement has been terminated.