0

Right now, in smaller projects, I flounder between 3 approaches. I would like to choose one of them to use consistently.

I have put example code, with pros/cons below. But essentially, the 3 approaches boil down to:

  1. All DB work in controller
  2. DB instance passed from controller into ViewModel, and work done there
  3. DB created in ViewModel with (using), and work done there

Why would an experienced developer choose one approach over another?

Are there any benefits / disadvantages to these approaches that - as a beginner - I might not be aware of?


Update

I appreciate that these patterns may not be used in larger projects which tend to me more structurally complex.

But really I am interested in the difference in them when they ARE used.



Approach One

All DB work and vaildation flow in controller

Makes it easy to grasp what's going on for simple applications...

...but 'fat' controllers may obscure understanding for complex applications.

Default used by MS in MVC template

public class ModelOne
{
    public int ID { get; set; }
    public string PropA { get; set; }
    public string PropB { get; set; }
    public string PropC { get; set; }
    // etc...
}
public class EditModelOnePropAViewModel
{
    public EditModelOnePropAViewModel(ModelOne model)
    {
        ID = model.ID;
        PropA = model.PropA;
    }
    public string PropA { get; set; }
    public int ID { get; set; }
}

public class ControllerOne : Controller
{
    private ApplicationDbContext DB = new ApplicationDbContext() { };


    [HttpGet]
    public ActionResult Edit(int id)
    {
        var model = DB.ModelOneDbSet.FirstOrDefault(i => i.ID);
        var viewModel = new EditModelOnePropAViewModel(model);
        return View(viewModel);
    }
    [HttpPost]
    public ActionResult Edit(EditModelOnePropAViewModel postedModel)
    {
        if (ModelState.IsValid)
        {
            var model = DB.ModelOneDbSet.FirstOrDefault(i = i.ID == postedModel.ID);
            model.PropA = postedModel.PropA;
            DB.SaveChanges();
            return RedirectToAction("index");
        }
        return View(postedModel);
    }
}

Approach Two

DB passed into ViewModel from Controller

Controller is 'thin' and 'dumb'.

Because we are using the controller's DB instance, it's Dispose() method will be called on the DB object.

public class ModelTwo
{
    public int ID { get; set; }
    public string PropA { get; set; }
    public string PropB { get; set; }
    public string PropC { get; set; }
    // etc...
}
public class EditModelTwoPropAViewModel
{
    public EditModelTwoPropAViewModel(ApplicationDbContext db, int id)
    {
        ID = id;
        PropA = db.ModelTwoDbSet
            .Where(i => i.ID == id)
            .Select(i => i.PropA)
            .FirstOrDefault();
    }

    public void SaveChanges(ApplicationDbContext db)
    {
        var modelTwo = db.ModelTwoDbSet.FirstOrDefault(i => i.ID == ID);
        modelTwo.PropA = PropA;
        db.SaveChanges();
    }
    public string PropA { get; set; }
    public int ID { get; set; }
}

public class ControllerTwo : Controller
{
    private ApplicationDbContext DB = new ApplicationDbContext() { };

    [HttpGet]
    public ActionResult Edit(int id)
    {
        var viewModel = new EditModelTwoPropAViewModel(DB, id);
        return View(viewModel);
    }
    [HttpPost]
    public ActionResult Edit(EditModelTwoPropAViewModel postedModel)
    {
        if (ModelState.IsValid)
        {
            postedModel.SaveChanges(DB);
            return RedirectToAction("index");
        }
        return View(postedModel);
    }
}

Approach Three

Same as Two, but DB created with (using) in ViewModel.

public class ModelThree
{
    public int ID { get; set; }
    public string PropA { get; set; }
    public string PropB { get; set; }
    public string PropC { get; set; }
    // etc...
}
public class EditModelThreePropAViewModel
{
    public EditModelThreePropAViewModel(int id)
    {
        using (var db = new ApplicationDbContext())
        {
            ID = id;
            PropA = db.ModelThreeDbSet
                .Where(i => i.ID == id)
                .Select(i => i.PropA)
                .FirstOrDefault();
        }
    }

    public void SaveChanges()
    {
        using (var db = new ApplicationDbContext())
        {
            var modelThree = db.ModelThreeDbSet.FirstOrDefault(i => i.ID == ID);
            modelThree.PropA = PropA;
            db.SaveChanges();
        }

    }
    public string PropA { get; set; }
    public int ID { get; set; }
}

public class ControllerThree : Controller
{
    [HttpGet]
    public ActionResult Edit(int id)
    {
        var viewModel = new EditModelThreePropAViewModel(id);
        return View(viewModel);
    }
    [HttpPost]
    public ActionResult Edit(EditModelThreePropAViewModel postedModel)
    {
        if (ModelState.IsValid)
        {
            postedModel.SaveChanges();
            return RedirectToAction("index");
        }
        return View(postedModel);
    }
}
Martin Hansen Lennox
  • 2,837
  • 2
  • 23
  • 64
  • Your question have many different answers based upon the size of the project. – Abbas Amiri Dec 06 '15 at 18:32
  • Could you give any more details - say for example with a relatively small, and relatively large project? Which would be favourable in each example? – Martin Hansen Lennox Dec 06 '15 at 18:44
  • 1
    I can only say that for large projects none of those approaches are good because there are more components that should come to play and it completely changes your architectural approach. – Abbas Amiri Dec 06 '15 at 18:59
  • Like a repository for example. And for smaller projects... does it make any difference which I use? – Martin Hansen Lennox Dec 06 '15 at 19:29
  • 1
    Not just Repository, Layering, Modules, Tiers, Logging, Exception Handling, Dependency injection, Monitoring, etc. The composition of them in large projects can be very complicated and yes it is completely different. – Abbas Amiri Dec 06 '15 at 19:56
  • 1
    Thanks Abbas Amiri. With this in mind, I'm changing the scope of the question to focus more on smaller projects. – Martin Hansen Lennox Dec 06 '15 at 20:15

1 Answers1

1

Your question is too vast and includes lots of different aspects. So I try to give you a very general view. There is nothing wrong or right in software design. There are "Project needs and specifications". But generally it has been accepted using "Design Patterns and Principles" makes project more robust,reliable and easy to maintain and make your code "loosely coupled and highly cohesive".

Having these in your mind, I give my opinion for your selections:

  1. All DB work in controller: This is good for small project that possibility for its expansion in future is low. It is easy to setup and easy to understand for other developers who join later. It is not good for project that need to change database later, which in that case you need to rewrite all your methods and probably your views. Another weakness of this approach is repetitive code for every object you need to add.
  2. DB instance passed from controller into ViewModel, and work done there: For my understanding from you code, you tried add a layer for your project to have all database actions there. It is good if you need to change your data,database or preventing from repetitive code. If you want that, it is better to use another project in you solution,known as "Multi tier architect ", to have more flexibility and "loosely coupled" sections. In that case you could easily replace your database project with other one later without worrying about your views and controllers, in multi tier architect knows as presentation layer.
  3. DB created in ViewModel with (using), and work done there: This isn't new approach. Having "Using block" in your code is about "thread starvation" (more information here).

At the end, consider your project needs and specifications, design your architecture and follow your architecture based on "Design Patterns and Principles". For more information about Design Patterns, I recommend the book "Professional ASP.NET Design Patterns" from "Scott Millett".

Community
  • 1
  • 1
Hadee
  • 1,392
  • 1
  • 14
  • 25
  • Thanks Hadee. From my little knowledge I agree with what you're saying. This is just a smaller project so I don't really want to over architect it - creating tiers,using DI, etc etc. I was really more wondering what the difference / implications of the 3 alternatives I suggested were. And in the example shown, does it make any difference which one I use? – Martin Hansen Lennox Dec 07 '15 at 20:11
  • As an aside... from what I read here on SO, many coding hours are spent to code in a way that allows a project 'can change database later'. But - in reality - how often does that actually happen? – Martin Hansen Lennox Dec 07 '15 at 20:14
  • It is not just about changing database.More important for me, It is how you could manage your project easily and how you could maintain your future changes. Think about which approach gives you best answer on them. That will be the best for you. Don't think too much about "professionalism"! .Your project grows by time and gets more mature. So just think about your project!. – Hadee Dec 07 '15 at 20:57