实体框架:更新具有 IEnumerable 属性的实体时出错。 'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException'
Posted
技术标签:
【中文标题】实体框架:更新具有 IEnumerable 属性的实体时出错。 \'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException\'【英文标题】:Entity Framework: Error updating an Entity with IEnumerable property. 'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException'实体框架:更新具有 IEnumerable 属性的实体时出错。 'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException' 【发布时间】:2021-01-09 08:59:29 【问题描述】:我正在 ASP.NET Core 中开发我的第一个 webapi。我有两个实体:
public class Event : Entity
private ISet<Ticket> _tickets = new HashSet<Ticket>();
public string Name get; protected set;
public string Description get; protected set;
public DateTime StartDate get; protected set;
public DateTime EndDate get; protected set;
public DateTime CreatedAt get; protected set;
public DateTime UpdatedAt get; protected set;
public IEnumerable<Ticket> Tickets => _tickets;
//.....
public void AddTickets(int amount, decimal price)
var seating = _tickets.Count + 1;
for (var i = 0; i < amount; i++)
_tickets.Add(new Ticket(this, seating, price));
seating++;
public class Ticket : Entity
public Guid EventId get; protected set;
public decimal Price get; protected set;
//... and other properties
当我尝试创建新活动并为其分配门票时:
public class EventController : Controller
[HttpPost]
public async Task<IActionResult> AddEvent([FromBody] CreateEventCommand createEventCommand)
createEventCommand.Id = Guid.NewGuid();
await _eventService.AddAsync(createEventCommand.Id,
createEventCommand.Name,
createEventCommand.Description,
createEventCommand.StartDate,
createEventCommand.EndDate);
await _eventService.AddTicketAsync(createEventCommand.Tickets,
createEventCommand.Price,
createEventCommand.Id);
return Created($"/events/createEventCommand.Name", null);
public class EventService : IEventService
public async Task AddAsync(Guid id, string name, string description, DateTime startDate, DateTime endDate)
var @event = await _eventRepository.GetAsync(id);
if(@event != null)
throw new Exception($"Event with this id: @event.Id already exist");
var eventToAdd = new Event(id, name, description, startDate, endDate);
await _eventRepository.AddAsync(eventToAdd);
public async Task AddTicketAsync(int amount, decimal price, Guid eventId)
var @event = await _eventRepository.GetAsync(eventId);
if (@event == null)
throw new Exception($"Event with this id: @event.Id already exist");
@event.AddTickets(amount, price);
await _eventRepository.UpdateAsync(@event);
public class EventRepository : IEventRepository
public async Task AddAsync(Event @event)
_context.Events.Add(@event);
await _context.SaveChangesAsync();
public async Task UpdateAsync(Event @event)
_context.Events.Update(@event);
await _context.SaveChangesAsync();
在Tickets表上执行的查询是
UPDATE [Tickets] SET [EventId] = @p700, [Price] = @p701, [PurchasedAt] = @p702, [Seating] = @p703, [UserId] = @p704, [Username] = @p705
WHERE [Id] = @p706;
SELECT @@ROWCOUNT;
之后会抛出异常:
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded.
我的问题是:在这种情况下不应该是 INSERT 查询而不是 UPDATE 吗?在这种情况下并发问题的原因可能是什么?我是 .NET 的新手,一般来说是并发,如果有任何帮助,我将不胜感激。
【问题讨论】:
您可以将 Ticket.Id 属性配置为 ValueGeneratedNever[DatabaseGenerated(DatabaseGeneratedOption.None)]
。
您不是通过 context.Tickets.Add() 添加票证,而是将它们添加到 event.Tickets 集合中。所以它们没有设置为添加的实体状态。相反,它们在逻辑上未被跟踪。在这种情况下,更改跟踪器将未跟踪的实体视为已修改。
感谢您的评论。看起来你是对的。如果我在一个步骤中添加带有门票的事件(context.Events.AddAsync(//带有门票的事件)然后 SaveAsync()它工作正常。如果它按顺序发生:'添加事件>保存>更新事件实体使用票>保存'然后我得到一个错误。我该如何更改更改跟踪器的行为呢?通过添加:.UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll)) 到 AddDbContext 方法中的选项它不起作用。
我想我根据您的第一条评论找到了原因。我所有的实体都继承自带有构造函数的 Entity 基类:protected Entity() Id = Guid.NewGuid();当我删除 Id 生成时,它工作正常......
我不确定这是否有意义,但看起来门票实体在生成时已经 Id != null 所以 EF 想要更新它们而不是插入新记录...跨度>
【参考方案1】:
在您的 AddTicketAsync 方法中,您检索 Event 对象的附加实体。
您应该能够通过调用 AddTickets 方法并在保存更改后对其进行更新。
@event.AddTickets(amount, price);
_eventRepository.your_context.SaveChangesAsync();
通过这种方式,您将保存更新后的事件实体的状态
您遇到并发错误,因为您正在尝试更新附加的实体。以下帖子可以帮助你How to update record using entity framework core?
【讨论】:
感谢您的回复。不幸的是它没有工作。仍然返回相同的错误... 你可以尝试分离你的 eventToAdd var entity = _context.Events.Add(@event); _context.detach(实体);等待 _context.SaveChangesAsync();以上是关于实体框架:更新具有 IEnumerable 属性的实体时出错。 'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException'的主要内容,如果未能解决你的问题,请参考以下文章
使用 AJAX 绑定时创建/更新后具有 IEnumerable 属性的 Kendo Grid 模型未正确更新