c# - 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
会引发异常。
解决方案
我认为它是 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
,因为您需要返回值的快照。这意味着如果您将一些项目添加到列表中,则快照实例必须保持不变。
推荐阅读
- java - 有没有办法使用并不总是设置所有属性的 WHERE 子句来查询 SQLite db?
- java - 为什么 pdf 查看器无法使用 iText?
- javascript - 如何调试 php return 和被调用的 ajax 成功函数之间发生了什么?
- node.js - 在 Mac 上使用 npm 全局安装firmata-party 失败
- regex - 在 pyspark 中使用 regexp_replace 反向引用命名组
- python - 没有反应返回或结束
- javascript - 我想弄清楚这里出了什么问题
- javascript - 简单的 Javascript 循环无法按预期工作
- anylogic - 为什么 agent.(parameter) 只在某些代码块中起作用?
- c++ - 来自 github 的现代 OpenGL 示例