Asp.net core 如何更新具有嵌套实体列表的现有实体?

Asp.net core 如何更新具有嵌套实体列表的现有实体?,asp.net-core,entity-framework-core,entity-framework-core-2.1,Asp.net Core,Entity Framework Core,Entity Framework Core 2.1,我尝试使用entity framework更新实体,但每次尝试更新时,都会引发一个错误,表示无法跟踪主类包含的嵌套实体 这些是我的课程: public abstract class BaseEntity { public int Id { get; set; } } 我用来更新的是Dashboard,它包含其余的类 我尝试使用一个通用服务层和一个通用存储库来实现这一点,它们的定义如下: public class GenericService<T> : IGener

我尝试使用entity framework更新实体,但每次尝试更新时,都会引发一个错误,表示无法跟踪主类包含的嵌套实体

这些是我的课程:

 public abstract class BaseEntity
 {
     public int Id { get; set; }
 }
我用来更新的是Dashboard,它包含其余的类

我尝试使用一个通用服务层和一个通用存储库来实现这一点,它们的定义如下:


public class GenericService<T> : IGenericService<T> where T : BaseEntity
{
    private readonly IBaseRepository<T> baseRepository;

    public GenericService(IBaseRepository<T> baseRepository)
    {
        this.baseRepository = baseRepository;
    }

    public async Task Update(T entity, T attachedEntity)
    {
        await baseRepository.Update(entity, attachedEntity);
    }
}


公共类GenericService:IGenericService其中T:BaseEntity
{
专用只读IBaseRepository存储库;
公共泛型服务(IBaseRepository baseRepository)
{
this.baseRepository=baseRepository;
}
公共异步任务更新(T实体、T附件身份)
{
等待baseRepository.Update(实体、附件);
}
}
public类BaseRepository:IBaseRepository其中T:BaseEntity
{
私有只读PortalContext dataContext;
私有DbSet DbSet{get;set;}
公共基本存储库(PortalContext上下文)
{
dataContext=context;
DbSet=dataContext.Set();
}
公共异步任务更新(T实体、T附件身份)
{
条目(AttacheIdentity).State=EntityState.Distached;
附加数据集(实体);
dataContext.Entry(entity).State=EntityState.Modified;
等待dataContext.SaveChangesSync();
}
}
最后,但并非最不重要的一点是,这就是我在Startup.cs上配置一切的方式

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<PortalContext>(
        options => options.UseSqlServer(Configuration.GetConnectionString("PortalContext"))
    );
    
    services.AddTransient(typeof(IGenericService<>), typeof(GenericService<>));
    services.AddTransient(typeof(IBaseRepository<>), typeof(BaseRepository<>));
    
    services.AddTransient<Func<string, ClaimsPrincipal, IRoleCheck>>((serviceProvider) =>
    {
        return (controllerName, claimsPrincipal) =>
                new RoleCheck(serviceProvider.GetRequiredService<IGenericService<Dossier>>(),
                serviceProvider.GetRequiredService<IGenericService<DossierTemplate>>(),
                serviceProvider.GetRequiredService<IGenericService<Dashboard>>(),
                controllerName, claimsPrincipal);
    });
}
public void配置服务(IServiceCollection服务)
{
services.AddDbContext(
options=>options.UseSqlServer(Configuration.GetConnectionString(“PortalContext”))
);
AddTransient(typeof(IGenericService)、typeof(GenericService));
AddTransient(typeof(IBaseRepository)、typeof(BaseRepository));
services.AddTransient((serviceProvider)=>
{
return(controllerName,claimsPrincipal)=>
新建RoleCheck(serviceProvider.GetRequiredService(),
serviceProvider.GetRequiredService(),
serviceProvider.GetRequiredService(),
控制人姓名、索赔人姓名);
});
}
应用程序首先要做的是调用RoleCheck类来检索和过滤所需的实体,然后用户可以更新它们

当我在控制器上调用更新函数时

 public async Task<ActionResult<Dashboard>> Put(int id, [FromBody] Dashboard dashboard)
 {
     var currentDashboard = await service.Get(id);
     if (currentDashboard == null)
     {
         return NotFound();
     }
    
     await service.Update(dashboard, currentDashboard);
     return Ok();

}
公共异步任务

我做错什么了吗?我已经坚持了一个星期了


提前感谢您,很抱歉我的文字太长,但我希望它说清楚。

我最终可以通过在我的存储库的Get()方法中添加.AsNoTracking()来解决这个问题:

public async Task<T> Get(int id, Func<IQueryable<T>, IIncludableQueryable<T, object>> includes)
{
    IQueryable <T> query = DbSet.AsNoTracking();
    if (includes != null)
    {
        query = includes(query);
    }
    return await query.FirstOrDefaultAsync(m => m.Id == id);
}
public异步任务Get(int-id,Func-includes)
{
IQueryable query=DbSet.AsNoTracking();
如果(包括!=null)
{
查询=包括(查询);
}
返回wait query.FirstOrDefaultAsync(m=>m.Id==Id);
}

我建议在附加失败时捕获此异常,并使用
Find
在ChangeTracker中查找已注册的实体。Get与更新有什么关系?您必须修复更新方法。
public class BaseRepository<T> : IBaseRepository<T> where T : BaseEntity
{
    private readonly PortalContext dataContext;

    private DbSet<T> DbSet { get; set; }

    public BaseRepository(PortalContext context)
    {
        dataContext = context;
        DbSet = dataContext.Set<T>();
    }

    public async Task Update(T entity, T attachedEntity)
    {
        dataContext.Entry(attachedEntity).State = EntityState.Detached;
        DbSet.Attach(entity);
        dataContext.Entry(entity).State = EntityState.Modified;
        await dataContext.SaveChangesAsync();
    }
}
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<PortalContext>(
        options => options.UseSqlServer(Configuration.GetConnectionString("PortalContext"))
    );
    
    services.AddTransient(typeof(IGenericService<>), typeof(GenericService<>));
    services.AddTransient(typeof(IBaseRepository<>), typeof(BaseRepository<>));
    
    services.AddTransient<Func<string, ClaimsPrincipal, IRoleCheck>>((serviceProvider) =>
    {
        return (controllerName, claimsPrincipal) =>
                new RoleCheck(serviceProvider.GetRequiredService<IGenericService<Dossier>>(),
                serviceProvider.GetRequiredService<IGenericService<DossierTemplate>>(),
                serviceProvider.GetRequiredService<IGenericService<Dashboard>>(),
                controllerName, claimsPrincipal);
    });
}
 public async Task<ActionResult<Dashboard>> Put(int id, [FromBody] Dashboard dashboard)
 {
     var currentDashboard = await service.Get(id);
     if (currentDashboard == null)
     {
         return NotFound();
     }
    
     await service.Update(dashboard, currentDashboard);
     return Ok();

}
public async Task<T> Get(int id, Func<IQueryable<T>, IIncludableQueryable<T, object>> includes)
{
    IQueryable <T> query = DbSet.AsNoTracking();
    if (includes != null)
    {
        query = includes(query);
    }
    return await query.FirstOrDefaultAsync(m => m.Id == id);
}