保存状态不清楚的对象图形的正确方法是什么?按状态,我的意思是说它们是新的还是现在的数据库条目正在被更新.
例如,如果我有:
public class Person { public int Id { get; set; } public int Name { get; set; } public virtual ICollection<Automobile> Automobiles { get; set; } } public class Automobile { public int Id { get; set; } public int Name { get; set; } public short Seats { get; set; } public virtual ICollection<MaintenanceRecord> MaintenanceRecords { get; set ;} public virtual Person Person { get; set; } } public class MaintenanceRecord { public int Id { get; set; } public int AutomobileId { get; set; } public DateTime DatePerformed { get; set; } public virtual Automobile Automobile{ get; set; } }
我正在编辑模型,类似于上述这些对象,然后将这些模型传递到数据层以保存,在这种情况下,我恰好是使用实体框架.所以我把这些模型翻译成DAL内部的POCO实体.
看来,除非我的模型有一个状态,指示它们是新的还是更新的,所以我有相当多的工作来“保存”更改.我必须首先选择Person实体,更新它,然后匹配任何现有的汽车,并更新那些并添加任何新的,然后为每个汽车检查任何新的或更新的维护记录.
有更快/更容易的方法吗?有可能我可以跟踪模型状态,我认为这对我有帮助,但这意味着我更愿意避免的数据层之外的代码的更改.我只是希望有一种使用方式,我可以按照这样的更新.
解决方法
我遇到这个问题一回,并在EF Codeplex网站上关注这个线程.
https://entityframework.codeplex.com/workitem/864
似乎正在考虑下一个版本,我假设EF 7,这显然是一个非常大的EF内部大修.这可能值得一试… http://www.nuget.org/packages/RefactorThis.GraphDiff/
回来当我在这个工作时,我发现了另一个EF在SO上的帖子,有人举例说明如何手动这样做.当时我决定手动做,不知道为什么,GraphDiff看起来很酷.这是我做的一个例子.
public async Task<IHttpActionResult> PutAsync([FromBody] WellEntityModel model) { try { if (!ModelState.IsValid) { return BadRequest(ModelState); } var kne = TheContext.Companies.First(); var entity = TheModelFactory.Create(model); entity.DateUpdated = DateTime.Now; var currentWell = TheContext.Wells.Find(model.Id); // Update scalar/complex properties of parent TheContext.Entry(currentWell).CurrentValues.SetValues(entity); //We don't pass back the company so need to attached the associated company... this is done after mapping the values to ensure its not null. currentWell.Company = kne; // Updated geometry - ARGHHH NOOOOOO check on this once in a while for a fix from EF-Team https://entityframework.codeplex.com/workitem/864 var geometryItemsInDb = currentWell.Geometries.ToList(); foreach (var geometryInDb in geometryItemsInDb) { // Is the geometry item still there? var geometry = entity.Geometries.SingleOrDefault(i => i.Id == geometryInDb.Id); if (geometry != null) // Yes: Update scalar/complex properties of child TheContext.Entry(geometryInDb).CurrentValues.SetValues(geometry); else // No: Delete it TheContext.WellGeometryItems.Remove(geometryInDb); } foreach (var geometry in entity.Geometries) { // Is the child NOT in DB? if (geometryItemsInDb.All(i => i.Id != geometry.Id)) // Yes: Add it as a new child currentWell.Geometries.Add(geometry); } // Update Surveys var surveyPointsInDb = currentWell.SurveyPoints.ToList(); foreach (var surveyInDb in surveyPointsInDb) { // Is the geometry item still there? var survey = entity.SurveyPoints.SingleOrDefault(i => i.Id == surveyInDb.Id); if (survey != null) // Yes: Update scalar/complex properties of child TheContext.Entry(surveyInDb).CurrentValues.SetValues(survey); else // No: Delete it TheContext.WellSurveyPoints.Remove(surveyInDb); } foreach (var survey in entity.SurveyPoints) { // Is the child NOT in DB? if (surveyPointsInDb.All(i => i.Id != survey.Id)) // Yes: Add it as a new child currentWell.SurveyPoints.Add(survey); } // Update Temperatures - THIS IS A HUGE PAIN = HOPE EF is updated to handle updating disconnected graphs. var temperaturesInDb = currentWell.Temperatures.ToList(); foreach (var tempInDb in temperaturesInDb) { // Is the geometry item still there? var temperature = entity.Temperatures.SingleOrDefault(i => i.Id == tempInDb.Id); if (temperature != null) // Yes: Update scalar/complex properties of child TheContext.Entry(tempInDb).CurrentValues.SetValues(temperature); else // No: Delete it TheContext.WellTemperaturePoints.Remove(tempInDb); } foreach (var temps in entity.Temperatures) { // Is the child NOT in DB? if (surveyPointsInDb.All(i => i.Id != temps.Id)) // Yes: Add it as a new child currentWell.Temperatures.Add(temps); } await TheContext.SaveChangesAsync(); return Ok(model); } catch (Exception ex) { Trace.WriteLine(ex.Message); } return InternalServerError(); }