Saya telah mengidentifikasi 3 situasi.
- Seorang siswa tanpa pendaftaran.
- Seorang siswa dengan pendaftaran tetapi tidak memiliki nilai.
- Seorang siswa dengan pendaftaran dan nilai.
Ada pemicu pada tabel pendaftaran untuk menghitung IPK. Jika seorang siswa memiliki nilai, itu akan memperbarui atau memasukkan entri ke dalam tabel IPK; tidak ada nilai, tidak ada entri tabel IPK.
Saya dapat menghapus siswa tanpa pendaftaran (# 1). Saya dapat menghapus seorang siswa dengan pendaftaran dan nilai (# 3 di atas). Tetapi saya tidak dapat menghapus seorang siswa dengan pendaftaran tetapi tidak ada nilai (# 2). Saya mendapatkan pelanggaran batasan referensi.
Pernyataan DELETE bertentangan dengan batasan REFERENSI "FK_dbo.GPA_dbo.Student_StudentID". Konflik terjadi di basis data "", tabel "dbo.GPA", kolom 'StudentID'.
Jika saya tidak dapat menghapus siswa baru tanpa pendaftaran (dan tidak ada entri IPK) maka saya akan memahami pelanggaran kendala, tetapi saya dapat menghapus siswa itu. Ini adalah siswa dengan pendaftaran dan tanpa nilai (dan masih tidak ada IPK) yang tidak dapat saya hapus.
Saya telah memperbaiki pemicu saya sehingga saya bisa maju. Sekarang, jika Anda memiliki pendaftaran, pemicu memasukkan Anda ke dalam tabel IPK, apa pun yang terjadi. Tapi saya tidak mengerti masalah yang mendasarinya. Penjelasan apa pun akan sangat dihargai.
Untuk apa nilainya:
- Visual Studio 2013 Professional.
- IIS express (internal ke VS2013).
- Aplikasi Web ASP.NET menggunakan EntityFramework 6.1.1.
- MS SQL Server 2014 Enterprise.
- GPA.Value tidak dapat dibatalkan.
- Enrollment.GradeID tidak dapat dibatalkan.
Berikut ini cuplikan dari basis data:
- EDIT -
Semua tabel dibuat oleh EntityFramework, saya menggunakan SQL Server Management Studio untuk menghasilkan ini.
Berikut adalah tabel buat pernyataan dengan kendala .:
GPA
meja:
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
meja:
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
meja:
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]
Inilah pemicunya :
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
Tambalan untuk bergerak maju adalah mengomentari garis-garis di AFTER INSERT
pelatuk itu.
Berikut adalah prosedur tersimpan :
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)));
Berikut adalah fungsi basis datanya :
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
Berikut ini adalah hasil debug dari metode hapus pengontrol, pernyataan pilih adalah metode yang menanyakan apa yang akan dihapus. Siswa ini memiliki 3 pendaftaran, REFERENCE
masalah kendala terjadi ketika pendaftaran ke-3 dihapus. Saya kira EF menggunakan transaksi karena pendaftaran tidak dihapus.
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.
sumber
Tanpa membaca semua, hanya dari diagram: Anda memiliki entri di Pendaftaran atau satu di IPK yang menunjuk ke Siswa yang ingin Anda hapus.
Entri dengan kunci asing harus dihapus terlebih dahulu (atau kunci diatur ke nol, tapi itu praktik buruk) sebelum Anda dapat menghapus entri Siswa.
Juga beberapa database memiliki ON DELETE CASCADE, yang akan menghapus semua entri dengan kunci asing ke yang ingin Anda hapus.
Cara lain adalah dengan tidak mendeklarasikannya sebagai kunci asing dan hanya menggunakan nilai kunci, tetapi itu juga tidak direkomendasikan.
sumber
ON DELETE CASCADE
pernyataan itu. Tidak satu pun dari pernyataan pembuatan tabel ini, maupun pernyataan penghapusan yang ditulis tangan, semuanya dihasilkan oleh entitasframework. Kaskade adalah karena pendaftaran memiliki kunci asing yang bukan kunci utama; Batasan kunci asing IPK adalah kunci primer sehingga tidak perlu kaskade. Saya sudah menguji ini, jika Anda menghapus seorang siswa dengan entri tabel IPK, entri itu akan dihapus. Satu-satunya masalah adalah siswa dengan pendaftaran tetapi tidak ada gpa.