我使用Entity Framework Core构建一个简单的webapi。我正在使用模型和视图模型来管理客户端实际接收的数据。这是我创建的模型和视图模型:
public class Team : BaseEntity
{
[Key]
public int TeamId { get; set; }
[Required]
public string TeamName { get; set; }
public List<TeamAgent> TeamAgents { get; set; }
}
public class TeamViewModel
{
[Required]
public int TeamId { get; set; }
[Required]
public string TeamName { get; set; }
[DataType(DataType.Date)]
public DateTime DateCreated { get; set; }
[DataType(DataType.Date)]
public DateTime DateModified { get; set; }
public List<TeamAgent> TeamAgents { get; set; }
}
public class TeamAgent : BaseEntity
{
[Key]
public int TeamAgentId { get; set; }
[ForeignKey("Agent")]
public int AgentId { get; set; }
[JsonIgnore]
public virtual Agent Agent { get; set; }
[ForeignKey("Team")]
public int TeamId { get; set; }
[JsonIgnore]
public virtual Team Team { get; set; }
[Required]
public string Token { get; set; }
}
public class TeamAgentViewModel
{
[Required]
public virtual AgentViewModel Agent { get; set; }
[Required]
public string Token { get; set; }
}
现在进行更新我在控制器中创建了一个Update方法:
[HttpPut("{id}")]
public async Task<IActionResult> Update(int id, [FromBody]TeamViewModel teamVM)
{
if (ModelState.IsValid)
{
var team = await _context.Teams
.Include(t => t.TeamAgents)
.SingleOrDefaultAsync(c => c.TeamId == id);
team.TeamName = teamVM.TeamName;
// HOW TO HANDLE IF SOME TEAMAGENTS GOT ADDED OR REMOVED???
_context.Teams.Update(team);
await _context.SaveChangesAsync();
return new NoContentResult();
}
return BadRequest(ModelState);
}
我遇到了如何更新连接到团队的TeamAgent的问题。我尝试和工作的一件事是删除所有TeamAgents,然后每次更新Team数据时创建新的TeamAgent。方法如下:
team.TeamAgents.Clear();
await _context.SaveChangesAsync();
team.TeamAgents.AddRange(teamVM.TeamAgents);
_context.Teams.Update(team);
await _context.SaveChangesAsync();
但这显然不是很好的方法。使用Entity Framework Core更新相关项目的正确方法是什么?
答案 0 :(得分:5)
Julie Lerman在2016年4月的文章Handling the State of Disconnected Entities in EF中提到了这一点。如果您还没有看到这篇文章,那么阅读是值得的。遗憾的是,从EF Core 2.0开始,仍然没有内置的方法来更新对象图。
Julie的文章中提到的方法是通过向对象添加属性并将状态发送到客户端来基本跟踪分离实体的状态。客户端可以修改状态并将其发送回服务器,然后您当然可以使用该信息做正确的事情。
在我最近的项目中,我采取了略微不同的方法,主要是因为到目前为止只有一个操作需要更新子集合。在我必须再次这样做的时候,我可能会将Julie的建议铭记于心并重构。
基本上它只是一个手动对象图更新,看起来非常类似于您使用EF 6.0的方法。需要注意的一点是,现在使用EF Core,您只需调用Remove()传递实体,而不必关心它所属的dbSet。
/// <param name="entity"></param>
public override void Update(Group entity) {
// entity as it currently exists in the db
var group = DbContext.Groups.Include(c => c.Contacts)
.FirstOrDefault(g => g.Id == entity.Id);
// update properties on the parent
DbContext.Entry(group).CurrentValues.SetValues(entity);
// remove or update child collection items
var groupContacts = group.Contacts.ToList();
foreach (var groupContact in groupContacts) {
var contact = entity.Contacts.SingleOrDefault(i => i.ContactId == groupContact.ContactId);
if (contact != null)
DbContext.Entry(groupContact).CurrentValues.SetValues(contact);
else
DbContext.Remove(groupContact);
}
// add the new items
foreach (var contact in entity.Contacts) {
if (groupContacts.All(i => i.Id != contact.Id)) {
group.Contacts.Add(contact);
}
}
DbContext.SaveChanges();
}
答案 1 :(得分:0)
为此向@Slauma致谢。
public void Update(UpdateParentModel model)
{
var existingParent = _dbContext.Parents
.Where(p => p.Id == model.Id)
.Include(p => p.Children)
.SingleOrDefault();
if (existingParent != null)
{
// Update parent
_dbContext.Entry(existingParent).CurrentValues.SetValues(model);
// Delete children
foreach (var existingChild in existingParent.Children.ToList())
{
if (!model.Children.Any(c => c.Id == existingChild.Id))
_dbContext.Children.Remove(existingChild);
}
// Update and Insert children
foreach (var childModel in model.Children)
{
var existingChild = existingParent.Children
.Where(c => c.Id == childModel.Id && c.Id != default(int))
.SingleOrDefault();
if (existingChild != null)
// Update child
_dbContext.Entry(existingChild).CurrentValues.SetValues(childModel);
else
{
// Insert child
var newChild = new Child
{
Data = childModel.Data,
//...
};
existingParent.Children.Add(newChild);
}
}
_dbContext.SaveChanges();
}
}
来源: