0

I'm learning .net MVC while developing a simple word list - Eg. When you learn a new language and create a list of words related to a certain topic.

I don't think I'm following the rules or good practices of the MVC architecture.

  1. It doesn't feel right that I pass the full Model to the view, which also contains methods. I think it should be just properties. Should I create a ViewModel or repository or both?
  2. Should Models contain methods?
  3. Should repositories contain methods?
  4. If models have contain methods, than the equivalent repository shouldn't and vice-versa?
  5. Can I chain calls? Eg. ListModel listModel = new ListModel(); listModel.GetListById(listId).SetOwnerId(222).save();?

My ListModel.cs:

using System;
using System.Collections.Generic;
using MySql.Data.MySqlClient;
using Dapper;
using System.ComponentModel.DataAnnotations;
using System.Linq;

namespace WordList.Models
{
    public class ListModel : BaseModel
    {
        public int listId { get; set; }
        [Required(ErrorMessage = "Name is required.")]
        public string name { get; set; }
        [Required(ErrorMessage = "Description is required.")]
        public string description { get; set; }
        [Required(ErrorMessage = "Language is required.")]
        public string language { get; set; }
        public int ownerId { get; set; }
        public DateTime date_created { get; set; }
        public DateTime date_updated { get; set; }

        public List<ListModel> GetAllLists()
        {
            using (MySqlConnection connection = new MySqlConnection(this.connStr))
            {
                return connection.Query<ListModel>("SELECT * FROM projectx.lists").AsList();
            }
        }

        public ListModel GetListById(int _listId)
        {
            using (MySqlConnection connection = new MySqlConnection(this.connStr))
            {
                return connection.Query<ListModel>("SELECT * FROM projectx.lists WHERE listId = @listId",
                    new {listId = _listId}
                ).FirstOrDefault();
            }
        }
    }
}

Here is my WordModel.cs:

using System;
using System.Collections.Generic;
using MySql.Data.MySqlClient;
using Dapper;
using System.ComponentModel.DataAnnotations;

namespace WordList.Models
{
    public class WordModel : BaseModel
    {
        public int wordId { get; set; }
        public string listId { get; set; }
        [Required(ErrorMessage = "word is required.")]
        public string word { get; set; }
        [Required(ErrorMessage = "Description is required.")]
        public string description { get; set; }


        public List<WordModel> GetWordsByListId(int _listId)
        {
                //this.connStr comes from the BaseModel
                using (MySqlConnection connection = new MySqlConnection(this.connStr))
                {
                    return connection.Query<WordModel>("SELECT * FROM projectx.words WHERE listId = @listId", 
                        new { listId = _listId }
                    ).AsList();
                }

        }
    }
}

Here is my Action in the controller that invokes the model:

public ActionResult Index(int listId)
{
    ListModel listModel = new ListModel().GetListById(listId);
    if (!String.IsNullOrEmpty(listModel.name))
    {
        ViewData["ListName"] = listModel.name;
        ViewData["ListDescription"] = listModel.description;
        WordModel wordModel = new WordModel();
        return View(wordModel.GetwordsByListId(realId));
    }
    else
    {
        ViewData["Message"] = "List doesn't exist";
        return View();
    }
}
  • 1
    I have a couple of answers to other questions that may provide some insight, here and here. – Eric King Jul 18 '16 at 18:25
4
  1. Yes your feeling is good. It's not right to have such methods inside Model.

    1a. Models should only contain properties (in my opinion).

    1b. Data-related methods like your SQL fetching should be encapsulate within Repositories. Repository pattern helps abstracting out the database connections we are using. Says you have dozens of models like this, and one day you decide to use SQL Server instead of MySQL, or employ EntityFramework, it's better to just change it in 1 place.

    1c. The usage of ViewModels is to contains view-ready information, when Models most likely will just a reflection of your database. Take example, assume that you want to differentiate the words based on how popular they are in a certain topic (most popular words will be styled as green, common words yellow and rare words red); you'd have a properties called "Popularity". In that case, your WordModel will have Popularity as an int, when WordViewModel will have a ColorType properties, which is translated from Popularity by Controller. Some like to have Models and ViewModels at the same time, some will only create ViewModels whenever necessary. It's your call.

  2. No.

  3. Definitely yes. All the methods above (GetAllLists, GetListById, GetWordsByListId, etc.) should be the repository's methods.

  4. It's always Model-no,Repo-yes. No vice versa.

  5. IMO, chain calls should be use in very special cases; if you are unsure when to use, I'd recommend not to use at all. Your example is a case where chain call should NOT be used. It makes your code vulnerable to edge cases and debugging it is hell (think about one tiny line in any of the chained functions throw an exception, will you right away know where it is?).

To sum up, I urge you to watch this basic video about repository pattern: https://www.youtube.com/watch?v=rtXpYpZdOzM

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.