There has to be a better way to handle child Saving/Updating in EF 6. Surely this duplication is just a failure on my part.
Entity
public partial class MyParentType
{
public MyParentType()
{
this.children = new HashSet<child>();
}
public int parentID { get; set; }
public virtual ICollection<child> children { get; set; }
}
Add/Update
public class MyRepository : IMyRepository
{
private readonly IErrorLogger _logger;
private readonly CorporateEntities _context;
public MyRepository(IErrorLogger logger)
{
_logger = logger;
_context = new CorporateEntities();
}
public void Update(IEnumerable<MyParentType> parents)
{
try
{
Add(parents.Where(x => x.parentID == 0));
var updatedData = parents.Where(x => x.parentID != 0);
foreach (var parent in updatedData)
{
var original = _context.MyParentTypes.FirstOrDefault(x => x.parentID == parent.parentID);
_context.Entry(original).CurrentValues.SetValues(parent);
UpdateChildren(parent);
}
_context.SaveChanges();
}
catch (Exception exception)
{
_logger.Error(exception.Message, exception);
}
}
public void Add(IEnumerable<MyParentType> parents)
{
if (parents == null)
return;
try
{
_context.MyParentTypes.AddRange(parents);
_context.SaveChanges();
}
catch (Exception exception)
{
_logger.Error(exception.Message, exception);
}
}
private void UpdateChildren(MyParentType parent)
{
try
{
AddChildren(parent.children.Where(x => x.childID == 0));
var updatedData = parent.children.Where(x => x.childID != 0);
foreach (var child in updatedData)
{
var original = _context.children.FirstOrDefault(x => x.childID == child.childID);
_context.Entry(original).CurrentValues.SetValues(child);
}
_context.SaveChanges();
}
catch (Exception exception)
{
_logger.Error(exception.Message, exception);
}
}
private void AddChildren(IEnumerable<child> references)
{
try
{
_context.children.AddRange(references);
_context.SaveChanges();
}
catch (Exception exception)
{
_logger.Error(exception.Message, exception);
throw;
}
}
}
I feel like I shouldn't have to duplicate this or write a generic method to handle both cases. Did I miss something in the EF docuemtation where I can update a child entity with the parent one?
I recommend you use GraphDiff. With this library your Update
method would be as I show below:
public void Update(IEnumerable<MyParentType> parents)
{
try
{
Add(parents.Where(x => x.parentID == 0));
var updatedData = parents.Where(x => x.parentID != 0);
foreach (var parent in updatedData)
{
_context.UpdateGraph(parent, map => map.OwnedCollection(p => p.children));
}
_context.SaveChanges();
}
catch (Exception exception)
{
_logger.Error(exception.Message, exception);
}
}
This way you don't need to worry about manage the children's states.
If you don't want to use GraphDiff, then you need to manage the state of the children manually:
public void Update(IEnumerable<MyParentType> parents)
{
try
{
foreach (var parent in parents)
{
if(parent.Id==0)
{
_context.MyParentTypes.Add(parent);
}
else
{
//When you change the state to Modified all the scalar properties of the entity will be marked as modified
_context.Entry(parent).State = EntityState.Modified;
foreach(var child in parent.children)
{
context.Entry(child).State =child.Id>0? EntityState.Modified:EntityState.Added;
}
}
}
_context.SaveChanges();
}
catch (Exception exception)
{
_logger.Error(exception.Message, exception);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With