对于一个项目,我试图为给定的
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();
}
}
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)
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 的特定用例