首页 > 解决方案 > EF 核心 DbContext.Attach 引发错误参数类型不匹配

问题描述

当我想更新实体时,我遇到了这个问题,这是我的存储库类:

private readonly CourseDbContext _dbContext;
    public CourseRepository(CourseDbContext dbContext) : base(dbContext)
    {
        _dbContext = dbContext;
    }
 public async Task<Domain.Models.Course> GetAsync(Guid id, CancellationToken token)
    {
        return await _dbContext.Courses.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, token);
    }
   public async Task UpdateAsync(Domain.Models.Course model, CancellationToken token)
    {
        model.ModifiedAt = DateTimeOffset.Now;

        EntityEntry<Domain.Models.Course> entry = _dbContext.Attach(model);

        entry.Property(m => m.SeqId).IsModified = false;
        entry.Property(m => m.CreatedAt).IsModified = false;

        _dbContext.Update(model);

        await _dbContext.SaveChangesAsync(token).ConfigureAwait(false);
    }

这是我的 CourseDbContext 类:

  public class CourseDbContext : DbContext
{
    public CourseDbContext(DbContextOptions options) : base(options)
    {

    }
 protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new CourseConfiguration());
    }
//add dbsets
   }

注册 CourseDbContext:

  services.AddDbContextPool<CourseDbContext>(options =>
        {
            options.UseSqlServer(configuration.GetValue<string>("CourseMSSQL"));
            options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
        }, 1024);

我的控制器:

 [HttpPut("{id:guid}")]
    public async Task UpdateAsync(Guid id, [FromForm] CourseCreateRequest request)
    {
        var entity = await _repository.GetAsync(id, HttpContext.RequestAborted);
        await _repository.UpdateAsync(entity, HttpContext.RequestAborted);
    }

当我尝试更新课程实体时,会EntityEntry<Domain.Models.Course> entry = _dbContext.Attach(model);引发此异常:

 "ClassName": "System.ArgumentException",
        "Message": "Argument types do not match",
        "Data": null,
        "InnerException": null,
        "HelpURL": null,
        "StackTraceString": "   at System.Linq.Expressions.Expression.Condition(Expression test, Expression ifTrue, Expression ifFalse)\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SnapshotFactoryFactory.CreateSnapshotValueExpression(Expression expression, IPropertyBase propertyBase)\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SnapshotFactoryFactory.CreateSnapshotExpression(Type entityType, ParameterExpression parameter, Type[] types, IList`1 propertyBases)\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SnapshotFactoryFactory.CreateConstructorExpression(IEntityType entityType, ParameterExpression parameter)\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SnapshotFactoryFactory`1.Create(IEntityType entityType)\r\n   at Microsoft.EntityFrameworkCore.Metadata.Internal.EntityType.<>c.<get_OriginalValuesFactory>b__147_0(EntityType entityType)\r\n   at Microsoft.EntityFrameworkCore.Internal.NonCapturingLazyInitializer.EnsureInitialized[TParam,TValue](TValue& target, TParam param, Func`2 valueFactory)\r\n   at Microsoft.EntityFrameworkCore.Metadata.Internal.EntityType.get_OriginalValuesFactory()\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.OriginalValues..ctor(InternalEntityEntry entry)\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.EnsureOriginalValues()\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntrySubscriber.SnapshotAndSubscribe(InternalEntityEntry entry)\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable`1 forceStateWhenUnknownKey)\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode`1 node)\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode`1 node, Func`2 handleNode)\r\n   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState targetState, EntityState storeGeneratedWithKeySetTargetState, Boolean forceStateWhenUnknownKey)\r\n   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState(InternalEntityEntry entry, EntityState entityState)\r\n   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState)\r\n   at Microsoft.EntityFrameworkCore.DbContext.Attach[TEntity](TEntity entity)\r\n   at CLive.Course.Repository.Implementation.CourseRepository.UpdateAsync(Course model, CancellationToken token) in D:\\Projects\\clive\\src\\Course\\Course.Repository\\Implementation\\CourseRepository.cs:line 99\r\n   at CLive.Course.Api.Dashboard.Controllers.CourseController.UpdateAsync(Guid id, CourseCreateRequest request) in D:\\Projects\\clive\\src\\Course\\Course.Api.Dashboard\\Controllers\\CourseController.cs:line 173\r\n   at lambda_method(Closure , Object )\r\n   at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)"

本课程实体配置:

public class CourseConfiguration : ModelBaseConfiguration<Domain.Models.Course>
{
    public override void ConfigureDerived(EntityTypeBuilder<Domain.Models.Course> builder)
    {
        builder.Property(x => x.Title)
            .HasMaxLength(512).IsRequired();

        builder.Property(x => x.Field)
            .HasConversion(
                filed => filed.HasValue ? filed.Value.ToString("G") : null,
            stringValue => string.IsNullOrEmpty(stringValue) ? default : (Field)Enum.Parse(typeof(Field), stringValue));

        builder.Property(x => x.Grade)
            .HasConversion(
                grade => grade.HasValue ? grade.Value.ToString("G") : null,
                stringValue => string.IsNullOrEmpty(stringValue) ? default : (Grade)Enum.Parse(typeof(Grade), stringValue));

        builder.Property(x => x.CoverImage)
            .HasMaxLength(256);

        builder.Property(x => x.ThumbnailImage)
            .HasMaxLength(256);

        builder.HasOne(x => x.Teacher)
            .WithMany()
            .OnDelete(DeleteBehavior.Restrict);

        var courseSchedulersComparer = new ValueComparer<IList<CourseScheduler>>(
            (c1, c2) => c1.SequenceEqual(c2),
            c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
        c => c.ToList());

        builder.Property(x => x.CourseSchedulers)
            .HasConversion(listObject => Serialize(listObject),
                json => Deserialize<List<CourseScheduler>>(json))
            .Metadata.SetValueComparer(courseSchedulersComparer);


    }
}

我认为一切都很好,但我不知道为什么EF会引发异常。

标签: c#asp.net-coreentity-framework-core

解决方案


我认为它是 EF 中的一个错误,但您需要转换快照结果:

var courseSchedulersComparer = new ValueComparer<IList<CourseScheduler>>(
    (c1, c2) => c1.SequenceEqual(c2),
    c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
    c => (IList<CourseScheduler>)c.ToList()); // note: I have added cast (IList<CourseScheduler>);

您不能只返回相同的实例c => c,因为您需要返回值的快照。这意味着如果您将一些项目添加到列表中,则快照实例必须保持不变。


推荐阅读