使用 AutoMapper 更新实体时 EF Core 引发跟踪异常

问题描述 投票:0回答:1

我在带有 Identity 的 Blazor Web 应用程序(在 .NET 9 上)中针对 SQL Server 数据库使用 EF Core,并使用 AutoMapper 在数据库实体和从 API 发送到 API 的 DTO 之间进行转换。

我有由以下(简化)类表示的 ASP.NET Core Identity 用户:

public class User : IdentityUser 
{
    public int? CompanyId { get; set; }
    public virtual Company? Company { get; set; }
    // Other properties removed for clarity
}

用户可以与公司关联,也可以不与公司关联。

Company
类(再次简化)如下所示:

public class Company 
{
    public int Id { get; set; }
    public virtual ObservableCollection<User> Users { get; set; } = [];
}

我使用 AutoMapper 从数据库实体创建 DTO。 DTO 从 API 发出,新的/修改的 DTO 由 API 接收,转换为实体并保存到数据库。

DTO类基本上反映了实体,所以我不会在这里展示它们。

我的映射器配置如下...

public class AutoMapperProfile : Profile 
{
    public AutoMapperProfile() 
    {
        CreateMap<Company, CompanyDto>()
              .ReverseMap();
        CreateMap<User, UserDto>()
              .ReverseMap()
              // Next three rules to account for Identity storing the email four times
              .ForPath(entity => entity.NormalizedEmail, opt => opt.MapFrom(dto => dto.Email.ToUpper()))
              .ForPath(entity => entity.UserName, opt => opt.MapFrom(dto => dto.Email))
              .ForPath(entity => entity.NormalizedUserName, opt => opt.MapFrom(dto => dto.Email.ToUpper()));
    }
}

CompanyDto
被发送回 API 进行保存时,我尝试按如下方式修复用户...

public async Task SaveCompany(CompanyDto company) 
{
    if (company.Id == 0) 
    {
        context.Companies.Add(mapper.Map<Company>(company));
    } 
    else 
    {
        Company? dbCompany = await context.Companies
                                          .Include(c => c.Users)
                                          .SingleOrDefaultAsync(c => c.Id == company.Id);

        if (dbCompany is not null) 
        {
            mapper.Map(company, dbCompany);

            foreach (UserDto user in company.Users) 
            {
                User? dbUser = dbCompany.Users.SingleOrDefault(u => u.Id == user.ID);

                if (dbUser is null) 
                {
                    dbCompany.Users.Add(mapper.Map<User>(user));
                } 
                else 
                {
                    mapper.Map(user, dbUser);
                }

                context.Companies.Update(dbCompany);
            }
        }
    }

    await context.SaveChangesAsync();
}

我遇到的问题是,每当我尝试保存具有任何关联用户的公司时,我都会遇到异常:

无法跟踪实体类型“User”的实例,因为已跟踪具有相同键值 {'Id'} 的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

即使公司或与其关联的用户没有任何变化,也会发生这种情况。

我添加了以下代码来查看上下文中的内容,但没有输出任何内容,这意味着上下文尚未跟踪任何内容...

context.ChangeTracker
  .Entries()
  .Where(x => includeUnchanged || x.State != EntityState.Unchanged)
  .OrderBy(x => x.Entity.GetType().Name)
  .ForEach(x => {
    Console.WriteLine($"Entity ({x.Entity.GetType().Name}) has been {x.State.ToString()}");
  });

有人能解释我做错了什么吗?谢谢

c# asp.net-core entity-framework-core automapper .net-9.0
1个回答
0
投票

我认为该错误可能是由context.Update引起的。理论上,跟踪器在保存项目时应该能够自行识别。尝试删除更新并仅保留

SaveChangesAsync

© www.soinside.com 2019 - 2024. All rights reserved.