views:

54

answers:

2

Lets say I have the following entities that map to database tables (every matching property name can be considered a PK/FK relationship):

public class Person
{
  public int PersonID { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
}

public class Employee
{
  public int EmployeeID { get; set; }
  public int PersonID { get; set; }
  public int Salary { get; set; }
}

public class Executive
{
  public int ExecutiveID { get; set; }
  public int EmployeeID { get; set; }
  public string OfficeNumber { get; set; }
}

public class Contact
{
  public int ContactID { get; set; }
  public int PersonID { get; set; }
  public string PhoneNumber { get; set; }
}

My architecture is as follows: Controller calls Service layer which calls Repository layer.

I have a View called AddExecutive that collects the following information: FirstName, LastName, PhoneNumber, Salary, and OfficeNumber.

What is the best way to commit this data given my architecture? I am thinking I that I would post up a ViewModel that contains all the information I collected and pass it off to a Service method AddExecutive(AddExecutiveViewModel addExecutiveViewModel), then within the Service method I would create new instances of Person, Employee, Executive, and Contact and attach them to each other (Person object) and pass ALL the data off to a Repository method AddExecutive(Person person). The Repository method would then simply commit the data. Does that sound right? What would be a better solution?

+2  A: 

So long as you maintain separation of concerns you good. Controller: Binds data to service / model Service: Enforces Business Logic, hands persistence to Repo Repo: performs ACID transactions and queries.

If your viewmodel is decoupled from any sort of framework concerns (i.e.: a POCO) You should be good since you maintain testability.

Slappy
My main concern as far as separation of concerns is concerned (hehe), is whether or not I should have a Service and Repository for each entity or not. Why would it be ok for me to only have an Executive Service and Repositiry? Is it because the other entities can be linked together?
Brian David Berman
No. A service has FUNCTIONAL concerns. (essentially a method for each user case, loosely speaking). A service takes information as an input, whether you do this via primitives or a custom class is up to you. If using a custom class, make sure it stays on message, I.E.: dont make a big ol state bag to pass your parameters in with.
Slappy
Would you consider the AddExecutiveViewModel that I described above as a "big ol state bag"?
Brian David Berman
Conceptually is it, but practically it isnt, since it is a decoupled purpose built class. Giving it a different name in essence will fix this. Try AddExecutive(ExecutiveViewModel executiveViewModel) hehe.
Slappy
Thanks. And you agree that the Service method is a good place to populate the true entity classes and pass them off (attached to a Person object) to the Repository?
Brian David Berman
Yes, the service can make multiple calls to a repo in one method.
Slappy
A: 

When you talk about committing data, you're talking about a unit of work. So start there:

public ActionResult AddExecutive(AddExecutiveViewModel addExecutiveViewModel)
{ 
    // simplified; no error handling
    using (var uow = new UnitOfWork()) // or use constructor injection on the controller...
    {
        // ???
        uow.Commit();
    }
    return RedirectToAction(// ...
}

Now your services come out of the unit of work (because both the unit of work and the repositories share an ObjectContext in the background; ObjectContext is the EF's "native" unit of work). So we can fill in the // ???:

public ActionResult AddExecutive(AddExecutiveViewModel model)
{ 
    // simplified; no error handling
    using (var uow = new UnitOfWork()) // or use constructor injection on the controller...
    {
        uow.EmployeeService.AddExecutive(model);
        uow.Commit();
    }
    return RedirectToAction(// ...
}

uow.Commit() is a thin shell around ObjectContext.SaveChanges(). The unit of work is injected with the same ObjectContext as the repositories. The services are EF-ignorant.

For a working (albeit in an early stage) example, see my open source repository/service project, Halfpipe.

Craig Stuntz