这两个实体是一对多关系(由代码第一个fluent api构建)。
public class Parent
{
public Parent()
{
this.Children = new List<Child>();
}
public int Id { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Data { get; set; }
}
在我的WebApi控制器中,我有创建父实体(工作正常)和更新父实体(有一些问题)的操作。更新操作如下所示:
public void Update(UpdateParentModel model)
{
//what should be done here?
}
目前我有两个想法:
获取一个被跟踪的父实体,命名为按模型存在的。Id,并将模型中的值逐个分配给实体。这听起来很愚蠢。在模型中。我不知道哪个子是新的,哪个子是修改的(甚至是删除的)。
通过模型创建一个新的父实体,并将其附加到DbContext并保存。但是DbContext如何知道子节点的状态(新增/删除/修改)呢?
实现这个功能的正确方法是什么?
如果你正在使用EntityFrameworkCore,你可以在你的控制器post动作中做以下事情(Attach方法递归地附加导航属性,包括集合):
_context.Attach(modelPostedToController);
IEnumerable<EntityEntry> unchangedEntities = _context.ChangeTracker.Entries().Where(x => x.State == EntityState.Unchanged);
foreach(EntityEntry ee in unchangedEntities){
ee.State = EntityState.Modified;
}
await _context.SaveChangesAsync();
假设每个被更新的实体都设置了所有属性,并在来自客户端的post数据中提供。不会为实体的部分更新工作)。
您还需要确保为该操作使用了一个新的/专用的实体框架数据库上下文。
下面的代码片段来自我的一个项目,我在其中实现了同样的事情。它将保存数据,如果有新的条目,更新,如果记录是不可用的张贴json。
Json数据来帮助你理解模式:
{
"groupId": 1,
"groupName": "Group 1",
"sortOrder": 1,
"filterNames": [
{
"filterId": 1,
"filterName1": "Name11111",
"sortOrder": 10,
"groupId": 1
} ,
{
"filterId": 1006,
"filterName1": "Name Changed 1",
"sortOrder": 10,
"groupId": 1
} ,
{
"filterId": 1007,
"filterName1": "New Filter 1",
"sortOrder": 10,
"groupId": 1
} ,
{
"filterId": 2,
"filterName1": "Name 2 Changed",
"sortOrder": 10,
"groupId": 1
}
]
}
public async Task<int> UpdateFilter(FilterGroup filterGroup)
{
var Ids = from f in filterGroup.FilterNames select f.FilterId;
var toBeDeleted = dbContext.FilterNames.Where(x => x.GroupId == filterGroup.GroupId
&& !Ids.Contains(x.FilterId)).ToList();
foreach(var item in toBeDeleted)
{
dbContext.FilterNames.Remove(item);
}
await dbContext.SaveChangesAsync();
dbContext.FilterGroups.Attach(filterGroup);
dbContext.Entry(filterGroup).State = EntityState.Modified;
for(int i=0;i<filterGroup.FilterNames.Count();i++)
{
if (filterGroup.FilterNames.ElementAt(i).FilterId != 0)
{
dbContext.Entry(filterGroup.FilterNames.ElementAt(i)).State = EntityState.Modified;
}
}
return await dbContext.SaveChangesAsync();
}
这是我的代码,工作得很好。
public async Task<bool> UpdateDeviceShutdownAsync(Guid id, DateTime shutdownAtTime, int areaID, decimal mileage,
decimal motohours, int driverID, List<int> commission,
string shutdownPlaceDescr, int deviceShutdownTypeID, string deviceShutdownDesc,
bool isTransportation, string violationConditions, DateTime shutdownStartTime,
DateTime shutdownEndTime, string notes, List<Guid> faultIDs )
{
try
{
using (var db = new GJobEntities())
{
var isExisting = await db.DeviceShutdowns.FirstOrDefaultAsync(x => x.ID == id);
if (isExisting != null)
{
isExisting.AreaID = areaID;
isExisting.DriverID = driverID;
isExisting.IsTransportation = isTransportation;
isExisting.Mileage = mileage;
isExisting.Motohours = motohours;
isExisting.Notes = notes;
isExisting.DeviceShutdownDesc = deviceShutdownDesc;
isExisting.DeviceShutdownTypeID = deviceShutdownTypeID;
isExisting.ShutdownAtTime = shutdownAtTime;
isExisting.ShutdownEndTime = shutdownEndTime;
isExisting.ShutdownStartTime = shutdownStartTime;
isExisting.ShutdownPlaceDescr = shutdownPlaceDescr;
isExisting.ViolationConditions = violationConditions;
// Delete children
foreach (var existingChild in isExisting.DeviceShutdownFaults.ToList())
{
db.DeviceShutdownFaults.Remove(existingChild);
}
if (faultIDs != null && faultIDs.Any())
{
foreach (var faultItem in faultIDs)
{
var newChild = new DeviceShutdownFault
{
ID = Guid.NewGuid(),
DDFaultID = faultItem,
DeviceShutdownID = isExisting.ID,
};
isExisting.DeviceShutdownFaults.Add(newChild);
}
}
// Delete all children
foreach (var existingChild in isExisting.DeviceShutdownComissions.ToList())
{
db.DeviceShutdownComissions.Remove(existingChild);
}
// Add all new children
if (commission != null && commission.Any())
{
foreach (var cItem in commission)
{
var newChild = new DeviceShutdownComission
{
ID = Guid.NewGuid(),
PersonalID = cItem,
DeviceShutdownID = isExisting.ID,
};
isExisting.DeviceShutdownComissions.Add(newChild);
}
}
await db.SaveChangesAsync();
return true;
}
}
}
catch (Exception ex)
{
logger.Error(ex);
}
return false;
}