无法跟踪实体类型“User”的实例,因为已跟踪具有相同键值的另一个实例。不是结构性的

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

对于一个项目,我试图为给定的

User
制作某个
Trainer
Club
。 为此,我创建了一个实体
Trainer
,它与
User
具有一对一的关系。 然后,俱乐部拥有用户和培训师集合。

将教练添加到俱乐部时一切都很顺利,并且他们已正确添加到数据库中。但是一旦我也向用户添加了某个角色,它就会给我一个

  System.InvalidOperationException: The instance of entity type 'User' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked
错误。

奇怪的是,第一次发送请求时,它起作用了,第二次它给出了这个错误。当我重新启动调试并再次执行端点时,它确实有效,但是当我升级另一个用户时,它再次出现此错误。

俱乐部导航道具

public IReadOnlyCollection<Trainer> Trainers => _trainers;
public IReadOnlyCollection<User> Members => _members;

用户导航道具

public IReadOnlyCollection<Trainer> Trainers => _trainers;

教练导航道具

public UserId UserId { get; private set; }
public User? User { get; private set; } 
public ICollection<Club> Clubs => _clubs;

用于创建培训师并添加用户角色的处理程序

    public async Task<Result> Handle(AddTrainerToClubCommand command,
        CancellationToken cancellationToken)
    {
        var club = await _clubRepository.FindByIdAsync(command.ClubId, 
            x => x.Include(club => club.Trainers).ThenInclude(t => t.User), cancellationToken: cancellationToken);
        
        if (club is null)
        {
            return Result.NotFound(typeof(Club));
        }
        
        // check if trainer is already trainer in club
        if (club.Trainers.Any(trainer => trainer.UserId.Equals(UserId.Create(command.AddTrainerToClubRequest.UserId))))
        {
            return Result.Failure(ClubErrors.TrainerAlreadyInClub);
        }
        
        var user = await _userRepository.FindByIdAsync(UserId.Create(command.AddTrainerToClubRequest.UserId), cancellationToken: cancellationToken);
        
        if (user is null)
        {
            return Result.NotFound(typeof(User));
        }
        
        var trainer = new Trainer(TrainerId.Create(Guid.NewGuid()), user);
        club.AddTrainer(trainer);
        
        await _trainerRepository.AddAsync(trainer, cancellationToken);
        await _unitOfWork.SaveChangesAsync(cancellationToken);

        return Result.Success();
    }
}

Trainer 构造函数内部

    public Trainer(TrainerId id,
        User user)
        : base(id)
    {
        UserId = user.Id;
        User = user;
        User.AddRole(Role.ClubTrainer); <-- once I add this line of code, it gives the error
    }

编辑: 我正在使用 ef-core 8.0.0。

角色是自定义实体

public class Role : Enumeration<Role>
{
    public static readonly Role RegisteredUser = new Role(1, "RegisteredUser");
    public static readonly Role DummyRole = new Role(2, "DummyRole");
    public static readonly Role ClubAdmin = new Role(3, "ClubAdmin");
    public static readonly Role ClubOwner = new Role(4, "ClubOwner");
    public static readonly Role ClubTrainer = new Role(5, "ClubTrainer");
    
    public Role(
        int id,
        string name)
        : base(id, name)
    {
    }

    public ICollection<Permission> Permissions { get; set; } = new List<Permission>();
    public ICollection<User> Users { get; set; } = new List<User>();
}

AddRole 只不过是用户实体中角色集合中的 Roles.add(role)

c# .net entity-framework dbcontext
1个回答
0
投票
        await _trainerRepository.AddAsync(trainer, cancellationToken);

使用“附加”而不是“添加”。

Add
告诉 EFC 将带有导航的整个对象显式添加到 ChangeTracker。如果没有任何对象被引入,这很好,但如果上下文中已经存在任何一个对象,则会抛出错误。

例如:ClubTrainer 是键为 5 的角色。如果您

Add
Fred 作为 ClubTrainer,Fred 对象和 ClubTrainer 对象都会添加到 ChangeTracker 中,状态为“已添加”。如果您随后
Add
Mary 作为 ClubTrainer,Mary 会被添加到 ChangeTracker,但 ChangeTracker 已经有一个 ID 为 5 的 ClubTrainer,因此它不能再次
Add
ClubTrainer。

使用

Attach
将添加任何尚不存在的对象,但会忽略上下文中已有的任何对象。使用
Attach
,Mary 将在 ChangeTracker 中标记为“已添加”,但 ClubTrainer 已存在于 ChangeTracker 中,并且 EFC 也会将该实例与 Mary 相关联。

另外说明,AddAsync 的用例非常有限。您应该使用 Add,除非您需要 AddAsync 的特定用例

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