4

I have seen some questions related to topic, but could not find answer for this scenario.

I have structure like
alt text

Part of my controller

//
// GET: /Person/Edit/5

public ActionResult Edit(int id)
{
    var viewModel = new PersonViewModel(PersonRepository.Get(id));
    return View(model);
}

//
// POST: /Person/Edit

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(PersonViewModel model)
{
    PersonRepository.Update(model.Person, model.Phones);
    return RedirectToAction("Index");
}

In my repository im doing something like this:

public void Update(Person person, ICollection<Phone> phones)
{
    using (var unitOfWork = UnitOfWork.Current)
    {
         Attach(contact);
         UpdatePhones(contact, phones);
         unitOfWork.Commit();
    }
}
public Person Attach(Person person)
{
     Context.AttachTo("Persons", entity);
     Context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
     return entity;
}
public void UpdatePhones(Person person, ICollection<Phone> phones)
{
    if (phones == null || phones.Count == 0) return;
    foreach (var phone in phones.Where(o => o.IsDeleted && !o.IsNew))
    {
         PhoneRepository.Delete(phone);
    }
    foreach (var phone in phones.Where(o => !o.IsDeleted && o.IsNew))
    {
         party.Phones.Add(phone);
    }
    foreach (var phone in phones.Where(o => !o.IsDeleted && !o.IsNew))
    {
         phone.PartyID = party.ID;
         PhoneRepository.Attach(phone);
    }
}

IsDeleted and IsNew are not persisted into db and used in dynamic form. PhonesRepository Attach() is same.

Im doing all of my updates like this because i need to reduce number of db calls as much as possible. Maybe there is a known best practice for this?

Thanks=)

Aleksei Anufriev
  • 3,206
  • 1
  • 27
  • 31

1 Answers1

4

That's not bad at all. Very similar to our setup.

Couple of pointers:

1 - Use generics for your Repositories. Your code for Attach is very simple, and should not need to be duplicated amongst entities. If you created a GenericRepository<T>, then your attach code would be:

public T Attach<T>(T entity) where T : class
{
     Context.GetEntitySet<T>.Attach(entity); // pluralization on (typeof)T.name to get entity set
     Context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
     return entity;
}

2 - I would seperate the UpdatePhones method into seperate methods. I wouldn't rely on a flag (IsDeleted, etc) to determine the course of action. I would be more explicit.

3 - Looks like you have a PhoneRepository? Why? Person is your aggregate root, and Phone is always related to a particular Person, therefore you should only have a PersonRepository in this aggregate boundary. You should be attaching to the Phones ObjectSet` of a particular person.

BTW - i assume you have lazy loading disabled? If not, those LINQ operations over the ICollection will cause silent round trips.

Apart from the above points (which are mainly design related), optimization-wise your code looks good to me.

And a final note - there is another recommended technique (Alex James) for updating entities in a detached context (aka MVC) called the "stub techinque".

I asked a question (and solved it myself) a few days ago if your interested, check it out.

HTH.

Community
  • 1
  • 1
RPM1984
  • 72,246
  • 58
  • 225
  • 350