EF Core выдает исключение отслеживания при обновлении объектов с помощью AutoMapperC#

Место общения программистов C#
Ответить
Anonymous
 EF Core выдает исключение отслеживания при обновлении объектов с помощью AutoMapper

Сообщение Anonymous »

Я использую EF Core для базы данных SQL Server в веб-приложении Blazor (на .NET 9) с Identity и использую AutoMapper для преобразования между сущностями базы данных и DTO, которые отправляются из и в базу данных. API.
У меня есть пользователи 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 Users { get; set; } = [];
}
Я использую AutoMapper для создания DTO из объектов базы данных. DTO отправляются из API, а новые/измененные DTO принимаются API, преобразуются в сущности и сохраняются в базе данных.
Классы DTO в основном отражают сущности, поэтому я не будут показывать их здесь.
Моя конфигурация картографа следующая...

Код: Выделить всё

public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap()
.ReverseMap();
CreateMap()
.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));
}
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));
}
else
{
mapper.Map(user, dbUser);
}

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

await context.SaveChangesAsync();
}
Проблема заключается в том, что всякий раз, когда я пытаюсь сохранить компанию, у которой есть связанные пользователи, я получаю исключение:

Экземпляр типа сущности «Пользователь» невозможно отследить, поскольку другой экземпляр с тем же значением ключа для {'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()}");
});
Кто-нибудь может объяснить, что я делаю неправильно? Спасибо


Подробнее здесь: https://stackoverflow.com/questions/792 ... automapper
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»