当我使用Entity Framework 6(首次使用EF)构建项目时,我注意到当我仅 Update
Entity
,EF的关系时也会更新主Entity
。
我可以说这种情况正在发生,因为我在System Versioned
上使用了Sql Server 2017
个表格。
这是一个弥补的场景,但大部分概念都在这里。
public async Task<ActionResult> Edit([Bind(Include="Id,Name,LocationTimes")] LocationViewModel locationVM) {
if (ModelState.IsValid) {
var location = await _db.Locations.FirstOrDefaultAsync(l => l.Id == locationsViewModel.Id && l.UserId == UserId);
if (location == null) {
return HttpNotFound();
}
location.Name = locationsViewModel.Name;
// ... other properties
foreach (var day in locationsViewModel.LocationTimes.Days) {
var time = new Time {
Day = day.Day,
OpenTime = day.OpenTime,
CloseTime = day.CloseTime,
};
// Find current Time or keep newly created
time = await time.FindByTimeAsync(time, _db) ?? time;
// Find LocationTime with same day
var locationTime = location.LocationTimes.FirstOrDefault(lt => lt.Time.Day == day.Day);
// If all times are the same, skip (continue)
if (locationTime != null && locationTime.Time.OpenTime == time.OpenTime && locationTime.Time.CloseTime == time.CloseTime)
continue;
if (locationTime != null && (locationTime.Time.OpenTime != time.OpenTime || locationTime.Time.CloseTime != time.CloseTime)) {
// Remove, At least one of the Times do not match
locationTime.Time = time;
_db.Entry(locationTime).State = EntityState.Modified;
} else {
location.LocationTimes.Add(new LocationTime {
Location = location,
Time = time,
});
}
}
_db.Entry(location).State = EntityState.Modified;
await _db.SaveChangesAsync();
return RedirectToAction("Index");
}
}
我假设,通过将整个Entity
标记为Modified
,EF将调用更新语句。
如果父作案中没有UPDATE
发生更改,我仍然可以避免向Entity
父properties
Add
发送Update
/ location
孩子的关系?
我假设我必须检查每个属性是否都没有更改,因此我不应该将Modified
状态设置为Times
,但是如何处理新添加的public async Task<ActionResult> Edit([Bind(Include="Id,Name,LocationTimes")] LocationViewModel locationVM) {
if (ModelState.IsValid) {
var location = await _db.Locations.FirstOrDefaultAsync(l => l.Id == locationsViewModel.Id && l.UserId == UserId);
if (location == null) {
return HttpNotFound();
}
/*******************
This is new part
*******************/
if (
location.Name != locationsViewModel.Name
// || ... test other properties
) {
location.Name = locationsViewModel.Name;
// ... other properties
_db.Entry(location).State = EntityState.Modified;
} else {
_db.Entry(location).State = EntityState.Unchanged;
}
/*******************/
foreach (var day in locationsViewModel.LocationTimes.Days) {
var time = new Time {
Day = day.Day,
OpenTime = day.OpenTime,
CloseTime = day.CloseTime,
};
// Find current Time or keep newly created
time = await time.FindByTimeAsync(time, _db) ?? time;
// Find LocationTime with same day
var locationTime = location.LocationTimes.FirstOrDefault(lt => lt.Time.Day == day.Day);
// If all times are the same, skip (continue)
if (locationTime != null && locationTime.Time.OpenTime == time.OpenTime && locationTime.Time.CloseTime == time.CloseTime)
continue;
if (locationTime != null && (locationTime.Time.OpenTime != time.OpenTime || locationTime.Time.CloseTime != time.CloseTime)) {
// Remove, At least one of the Times do not match
locationTime.Time = time;
_db.Entry(locationTime).State = EntityState.Modified;
} else {
location.LocationTimes.Add(new LocationTime {
Location = location,
Time = time,
});
}
}
/* removed, added above */
//_db.Entry(location).State = EntityState.Modified;
await _db.SaveChangesAsync();
return RedirectToAction("Index");
}
}
?< / p>
更新#1
所以我尝试了我提到的并且它有效,但这是正确的方法吗?
* def foo = 5
* assert foo <= 6
* def bar = { a: 1 }
* match bar == { a: '#? _ > 0' }
答案 0 :(得分:0)
因此,经过反复试验,我想我误解了EF如何处理EntityState
。我虽然child
是Modified
,但您必须将父级设为Modified
。
很高兴,情况并非如此,下面的代码可以正常工作。
public async Task<ActionResult> Edit([Bind(Include="Id,Name,LocationTimes")] LocationViewModel locationVM) {
if (ModelState.IsValid) {
var location = await _db.Locations.FirstOrDefaultAsync(l => l.Id == locationsViewModel.Id && l.UserId == UserId);
if (location == null) {
return HttpNotFound();
}
/*******************
This is new part
check if at least one property was changed
*******************/
if (
location.Name != locationsViewModel.Name
|| location.Ref != locationsViewModel.Ref
// || ... test other properties
) {
location.Name = locationsViewModel.Name;
location.Ref = locationsViewModel.Ref;
// ... other properties
// Tell EF that the Entity has been modified (probably not needed, but just in case)
_db.Entry(location).State = EntityState.Modified;
} else {
// Tell EF that the Entity has *NOT* been modified
_db.Entry(location).State = EntityState.Unchanged;
}
/*******************/
foreach (var day in locationsViewModel.LocationTimes.Days) {
var time = new Time {
Day = day.Day,
OpenTime = day.OpenTime,
CloseTime = day.CloseTime,
};
// Find current Time or keep newly created
time = await time.FindByTimeAsync(time, _db) ?? time;
// Find LocationTime with same day
var locationTime = location.LocationTimes.FirstOrDefault(lt => lt.Time.Day == day.Day);
// If all times are the same, skip (continue)
if (locationTime != null && locationTime.Time.OpenTime == time.OpenTime && locationTime.Time.CloseTime == time.CloseTime)
continue;
if (locationTime != null && (locationTime.Time.OpenTime != time.OpenTime || locationTime.Time.CloseTime != time.CloseTime)) {
// Remove, At least one of the Times do not match
locationTime.Time = time;
_db.Entry(locationTime).State = EntityState.Modified;
} else {
location.LocationTimes.Add(new LocationTime {
Location = location,
Time = time,
});
}
}
/* removed, added above */
//_db.Entry(location).State = EntityState.Modified;
await _db.SaveChangesAsync();
return RedirectToAction("Index");
}
}