在 EF Core 3.1 中删除多行时出错 "Failed to compare two elements in the array - At least one object must implement IComparable"

Error "Failed to compare two elements in the array - At least one object must implement IComparable" for delete multiple row in EF Core 3.1

我使用 EF Core 3.1,这是我的代码:

public async Task DeleteSessions(List<Guid> ids)
{
    var sessions = new List<Session>();
    foreach (var sessionId in ids)
    {
        var session = await _dbContext.Sessions.FindAsync(sessionId);
        sessions.Add(session);
    }

    _dbContext.Sessions.RemoveRange(sessions);

    // error occurred on this line
    await _dbContext.SaveChangesAsync();
}

但在 SaveChagedAsync 上抛出异常并出现此错误

Failed to compare two elements in the array - At least one object must implement IComparable

我也将代码更改为:

public async Task DeleteSessions(List<Guid> ids)
{
     foreach (var sessionId in ids)
     {
          var session = await _dbContext.Sessions.FindAsync(sessionId);
          _dbContext.Sessions.Remove(session);
     }

     // error occurred on this line
     await _dbContext.SaveChangesAsync();
 }

但没关系,SaveChagedAsync 方法再次抛出异常

如果我逐一删除并调用 SaveChangedAsync 该方法可以正常工作,但我需要在一个事务中删除多行。

为什么 EF Core 不支持多行删除?以及如何解决这个问题?

更多信息:

    public class Session
    {
        public BusinessId Id { get; private set; }

        public string Title { get; private set; }

        public DateTime StartDate { get; private set; }

        public int ExtraDurationAsMinute { get; private set; }

        public string LatestServerId { get; private set; }

        public Courses.Course Course { get; private set; }

        private Session()
        {
        }

        public static async Task<Session> Create(Guid sessionId, Courses.Course course, DateTime startDate, string title)
        {
            var session = new Session
            {
                Id = sessionId,
                Course = course
            };

            session.ChangeStartDate(startDate);
            session.ChangeTitle(title);

            return session;
        }

        public void ChangeServer(string serverId)
        {
            this.LatestServerId = serverId;
        }

        public void ChangeTitle(string title)
        {
            if (Title == title)
            {
                return;
            }

            this.Title = title;
        }

        public void ChangeStartDate(DateTime startDate)
        {
            if (StartDate == startDate)
            {
                return;
            }

            this.StartDate = startDate;

            Course.CalculateFirstAndLastSession();
        }

        public void ChangeExtraDuration(int duration)
        {
            if (ExtraDurationAsMinute == duration)
            {
                return;
            }

            ExtraDurationAsMinute = duration;

            Course.CalculateFirstAndLastSession();
        }

    }

这是 EF 会话配置:

public class SessionConfiguration : IEntityTypeConfiguration<Core.DomainModels.Sessions.Session>
    {
        public void Configure(EntityTypeBuilder<Core.DomainModels.Sessions.Session> builder)
        {
            builder.Property(x => x.Id)
                .HasConversion(x => x.Value,
                    x => BusinessId.FromGuid(x));

            builder.Property(x => x.LatestServerId).HasMaxLength(100);

            builder.HasOne(x => x.Course);
        }
    }

这是异常堆栈跟踪:

   at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer)
   at System.Array.Sort[T](T[] array, Int32 index, Int32 length, IComparer`1 comparer)
   at System.Collections.Generic.List`1.Sort(Int32 index, Int32 count, IComparer`1 comparer)
   at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.<BatchCommands>d__11.MoveNext()
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.<ExecuteAsync>d__8.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.<ExecuteAsync>d__8.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<SaveChangesAsync>d__97.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<SaveChangesAsync>d__101.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.EntityFrameworkCore.DbContext.<SaveChangesAsync>d__54.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at SilverPath.Infra.Data.Sql.Commands.BaseEntityFrameworkUnitOfWork`1.<CommitAsync>d__5.MoveNext() in O:\Projects\SpAzure\Elearno-Reborn\Institute\Develop\Framework\SilverPath.Infra.Data.Sql.Commands\BaseEntityFrameworkUnitOfWork.cs:line 32
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ElearnoInstitute.Core.ApplicationServices.Sessions.Command.SaveSessions.SaveSessionHandler.<Handle>d__2.MoveNext() in O:\Projects\SpAzure\Elearno-Reborn\Institute\Develop\Institute\src\Core\ElearnoInstitute.Core.ApplicationServices\Sessions\Command\SaveSessions\SaveSessionHandler.cs:line 83
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at SilverPath.Framework.EndPoints.Web.Controllers.BaseApiController.<Execute>d__11`1.MoveNext() in O:\Projects\SpAzure\Elearno-Reborn\Institute\Develop\Framework\SilverPath.EndPoints.Web\Controllers\BaseApiController.cs:line 66
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ElearnoInstitute.Endpoint.ClientApi.Controllers.V1.SessionController.<SaveSession>d__3.MoveNext() in O:\Projects\SpAzure\Elearno-Reborn\Institute\Develop\Institute\src\Endpoint\ElearnoInstitute.Endpoint.ClientApi\Controllers\V1\SessionController.cs:line 85
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.<Execute>d__0.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<<InvokeActionMethodAsync>g__Logged|12_1>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<<InvokeNextActionFilterAsync>g__Awaited|10_0>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<<InvokeInnerFilterAsync>g__Awaited|13_0>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<<InvokeNextResourceFilter>g__Awaited|24_0>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<<InvokeFilterPipelineAsync>g__Awaited|19_0>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<<InvokeAsync>g__Logged|17_1>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<<Invoke>g__AwaitRequestTask|6_0>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.<Invoke>d__5.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.<Invoke>d__6.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.<Invoke>d__5.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.<Invoke>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.<Invoke>d__3.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at SilverPath.Framework.EndPoints.Web.Middlewares.ApiExceptionHandler.ApiExceptionMiddleware.<Invoke>d__5.MoveNext() in O:\Develop\Framework\EndPoints.Web\Middlewares\ApiExceptionHandler\ApiExceptionMiddleware.cs:line 35

Ef 在更新行时需要一个确定的顺序,因为如果有两个线程更新相同的行并且顺序颠倒可能会导致死锁 看到这个 SaveChanges() deadlocks

所以

BusinessId should implement IComparable<BusinessId>

您的问题将得到解决:)