#.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