Entity Framework — как мне выяснить, что вызывает ошибку ссылочной целостности?

#.net #entity-framework

#.net #entity-framework

Вопрос:

Работая с entity framework, мой код использует LINQ для получения коллекции объектов, которые необходимо удалить из базы данных. Эта коллекция иногда довольно большая, в зависимости от обстоятельств — 30 или 40 объектов.

Я продолжаю пытаться отделить эти объекты от связанных с ними объектов, чтобы я мог их удалить, затем я вызываю context .DeleteObject() для каждого, а затем, наконец, context.SaveChanges().

В большинстве случаев это работает отлично, особенно когда коллекция объектов для удаления очень мала. Однако, когда он большой, этот код иногда выдает ошибку, связанную с ссылочной целостностью, в частности:

 The DELETE statement conflicted with the REFERENCE constraint 
"FK_ServiceFeatureSchemaFragmentSchemaFragment_SchemaFragment". 
The conflict occurred in database "MyDataBase", 
table "dbo.ServiceFeatureSchemaFragmentSchemaFragment".rn
The statement has been terminated. 
  

Похоже, что иногда мои объекты имеют дополнительные ограничения, которые я не могу найти и устранить перед удалением.

С чем я борюсь, так это с тем, что, поскольку я работаю с относительно большой коллекцией, я не могу определить, какая из них является причиной этого. Я ищу предложения относительно того, как я могу двигаться вперед, каким-то образом идентифицируя проблемные объекты, например, есть ли способ, которым вы можете заранее определить, будут ли объекты в коллекции выдавать такого рода ошибки, прежде чем удалять их? Или другой подход?

Предложения приняты с благодарностью.

Ответ №1:

Напишите хранимую процедуру в SQL Server, где вы сможете увидеть влияние ваших отношений FK / PK без дополнительного уровня сопоставления EF, чтобы запутать ситуацию. В этом примере используется либо ezUserID на основе целого числа из таблицы основного профиля пользователя, либо ASP.NET идентификатор пользователя для начала удаления.

Вы могли бы просто использовать каскадные удаления при определении ваших отношений …

 SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO


CREATE PROC [dbo].[ezUser_Delete]
    @ezUserID int = NULL,
    @UserName nvarchar(128) = NULL
AS
BEGIN
    SET NOCOUNT ON

    DECLARE @UserID uniqueidentifier;

    --DECLARE @TranName VARCHAR(20);   --Generally shouldn't use named transactions in stored procedures
    --SELECT @TranName = 'MyTransaction';
    SET XACT_ABORT ON

    IF @ezUserID IS NULL AND @UserName IS NULL RETURN 0

BEGIN TRY
    BEGIN TRANSACTION;

            IF ISNULL(@ezUserID, 0) > 0

                BEGIN
                    SELECT @UserID = UserID FROM ezUsers WHERE ezUserID = @ezUserID
                    SELECT @UserName = UserName FROM aspnet_Users WHERE UserID = @UserID 
                    IF (@UserName IS NULL)
                        BEGIN
                            ROLLBACK TRANSACTION;
                            RETURN -1
                        END
                END

            ELSE IF (LEN(ISNULL(@UserName,'')) > 0)

                BEGIN
                    SELECT @UserID = UserID FROM aspnet_Users WHERE UserName = @UserName
                    SELECT @ezUserID = ezUserID FROM ezUsers WHERE UserID = @UserID  
                    IF (@ezUserID IS NULL)
                        BEGIN
                            ROLLBACK TRANSACTION;
                            RETURN -1
                        END
                END

            ELSE 
                RETURN -1

            SELECT 'DELETE' AS [Command]
                , U.UserID
                , U.UserName
                , RoleName
                , M.Email
                , EU.ezUserID
                , EU.FirstName, EU.LastName
                , CallSign
                , Gender
                , UIR.RoleID

            FROM dbo.aspnet_Users U 
                    LEFT OUTER JOIN dbo.aspnet_Membership M ON U.UserID = M.UserID

                    LEFT OUTER JOIN dbo.ezUsers EU ON U.UserID = EU.UserID      

                    LEFT OUTER JOIN dbo.aspnet_UsersInRoles UIR ON U.UserID = UIR.UserID
                    LEFT OUTER JOIN dbo.aspnet_Roles R ON UIR.RoleID = R.RoleID     
            WHERE U.UserID = @UserID 

            IF @UserID IS NULL
                RETURN -1

            DELETE FROM dbo.ezUsersDating   WHERE ezUserID = @ezUserID  
            DELETE FROM dbo.ezUsersPhysicalIdentity WHERE ezUserID = @ezUserID

            DELETE FROM dbo.ezMessages WHERE AuthorID = @ezUserID

            DELETE FROM dbo.ezTheUsual WHERE ezUserID = @ezUserID
            DELETE FROM dbo.ezRentals WHERE ezUserID = @ezUserID

            DELETE FROM dbo.ezUsersSharedActivities WHERE ezUserID = @ezUserID

            DELETE FROM dbo.ezCurrentVehicle WHERE UVID IN (SELECT UVID FROM dbo.ezUsersVehicles WHERE ezUserID = @ezUserID)
            DELETE FROM dbo.ezDriverVehicles WHERE ezUserID = @ezUserID  -- Delete this Table
            DELETE FROM dbo.ezOwnerVehicles WHERE OwnerID = @ezUserID   
            DELETE FROM dbo.ezUsersVehicles WHERE ezUserID = @ezUserID

            DELETE FROM dbo.ezPL8Messages 
                WHERE PL8ID IN (
                SELECT PL8ID FROM dbo.ezPL8s WHERE VehicleID IN (SELECT VehicleID FROM dbo.ezVehicles WHERE CreatedBy = @ezUserID))

            DELETE FROM dbo.ezPL8s WHERE VehicleID IN (SELECT VehicleID FROM dbo.ezVehicles WHERE CreatedBy = @ezUserID)

            DELETE FROM dbo.ezPL8s_Vehicles WHERE VehicleID IN (SELECT VehicleID FROM dbo.ezVehicles WHERE CreatedBy = @ezUserID)

            DELETE FROM dbo.ezVehicles WHERE CreatedBy = @ezUserID

            DELETE FROM dbo.ezImages_Users
            WHERE ImageID IN (SELECT ImageID FROM dbo.ezImages 
                                WHERE UploadedBy = @ezUserID)

            DELETE FROM dbo.ezImages_Users
            WHERE ezUserID = @ezUserID

            DELETE FROM dbo.ezImages 
            WHERE UploadedBy = @ezUserID

            DELETE FROM dbo.ezPets
            WHERE ezUserID = @ezUserID

            DELETE FROM dbo.ezAccounts
            WHERE CPID IN (SELECT CPID FROM dbo.ezCompany_People WHERE ezUserID = @ezUserID)

            DELETE FROM dbo.ezCompany_People
            WHERE ezUserID = @ezUserID          

            DELETE FROM dbo.ezMedicals
            WHERE ezUserID = @ezUserID

            DELETE FROM dbo.ezVehicles WHERE CreatedBy = @ezUserID

            DELETE FROM dbo.ezParentChildren WHERE ParentID = @UserID OR ChildID = @UserID
            DELETE FROM dbo.ezEmergencyContacts WHERE ezUserID = @ezUserID

            DELETE FROM dbo.ezDriveThrus_Customers WHERE ezUserID = @ezUserID   

            DELETE FROM dbo.ezRelationshipsP2P WHERE RelFromID = @UserID OR RelToID = @UserID

            DELETE FROM [dbo].[ezPL8Meaning] WHERE ezUserID = @ezUserID

            DELETE FROM dbo.ezUsers WHERE UserID = @UserID 

            DELETE FROM dbo.aspnet_PersonalizationPerUser WHERE UserID = @UserID
            DELETE FROM dbo.aspnet_Profile WHERE UserID = @UserID
            DELETE FROM dbo.aspnet_UsersInRoles WHERE UserID = @UserID

            DELETE FROM dbo.aspnet_Membership WHERE UserID = @UserID    

            DELETE FROM dbo.aspnet_Users WHERE UserID = @UserID     

    COMMIT TRANSACTION;  
END TRY

BEGIN CATCH
    SELECT ERROR_NUMBER(), ERROR_MESSAGE();
    IF @@TRANCOUNT > 0  
        ROLLBACK TRANSACTION;

    RAISERROR('Error', 16, 1)
    RETURN 0
END CATCH

END 






GO