none
Creating ViewModels in MVC3 Models (EF Database first) instead of returning Entities? RRS feed

  • Question

  • Is it concidered bad practice or such to create and return ViewModels inside Models? I have some ViewModels that I simply populate with data from Models and I never use self-tracking entities, so I figured that I might just as well create my ViewModels inside my models. Is this ok?

    I can't really understand how to use EF 4 with my MVC 3 app, that's why I'm asking. Is this bad practice? EF seems a bit incompatible with MVC3 in that the DbContext object lifespan is hard to control imho. Please, if you have any suggestions other than creating ViewModels in Models directly and skipping working with entities entirely, your comments are more than welcome!

    My Models look like this mockup:

    // Partial, original generated from database.
    public partial Post {
        // snip
        public static UserPostsViewModel GetUserPosts(int id)
        {
            using (var ctx = new MyEntities()) {
                var upvm = new UserPostsViewModel();
                var usr = ctx.Users.find(id);
                upvm.User = usr;
                upvm.Posts = (from p in ctx.Posts
                             where p.user = usr.UserID
                             select p).toList();
                return upvm;
            }
        }
        // snip
    }

    Friday, May 18, 2012 5:28 PM

Answers

  •  This is a project in a Demo solution I have where the DAL.Article is
    doing everything for the entity Article. It uses the IDAL.Article and
    DTOArticle. The DTO is what is sent through the layers to the viewmodel
    of a WPF UI solution. The EF entity is left at the DAL. The DTO is sent
    back to the DAL to be mapped backed to an entity that is persisted. Of
    course the DAL is being called by the BLL that has an Article object
    that makes the calls.
     
    I would be more than happy to talk to you about the other pieces you
    will need like the Service Layer (I am not talking about a WEB service
    but it can be used with a Web service) and the BLL,
     
     
    using System.Linq;
    using DAL.IDAL;
    using DAL.Model;
    using DAL.DTO;
    using System.Data.EntityClient;
    using System.Collections.Generic;
     namespace DAL
    {
        public class Article :IArticle
        {
            private const string pcdb = "name=PublishingCompanyEntities";
             public DTOArticle GetArticleTop1()
            {
                var dto = new DTOArticle();
                 using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        var article = (from a in db.Articles select
    a).Take(1).First();
                         dto.ArticleID = article.ArticleID;
                        dto.AuthorID =  article.AuthorID;
                        dto.Body = article.Body;
                        dto.Tille = article.Title;
                     }
                    finally
                    {
                        conn.Close();
                    }
                }
                 return dto;
            }
             public DTOArticle GetArticle(int id)
            {
                var dto = new DTOArticle();
                 using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        var article = (from a in db.Articles.Where(a =>
                             a.ArticleID == id)select a).First();
                         dto.ArticleID = article.ArticleID;
                        dto.AuthorID =  article.AuthorID;
                        dto.Body = article.Body;
                        dto.Tille = article.Title;
                     }
                    finally
                    {
                        conn.Close();
                    }
                }
                 return dto;
            }
             public List<DTOArticle> GetArticles()
            {
                var dtos = new List<DTOArticle>();
                 using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        var articles = (from a in db.Articles select
    a).ToList();
                         dtos.AddRange(articles.Select(article => new DTOArticle
                        {
                            ArticleID = article.ArticleID,
                            AuthorID = (int) article.AuthorID,
                            Body = article.Body,
                            Tille = article.Title
                        }));
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
                 return dtos;
            }
             public void UpdateArticles(List<DTOArticle> articles)
            {
                using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        foreach (var article in articles)
                        {
                            var artc = new Model.Article { ArticleID =
    article.ArticleID };
                             db.AttachTo("Articles", artc);
                            artc.AuthorID = article.AuthorID;
                            artc.Title = article.Tille;
                            artc.Body = article.Body;
                            db.SaveChanges();
                        }
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
             public void AddArticles(List<DTOArticle> articles)
            {
                using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        foreach (var article in articles)
                        {
                            var artc = new Model.Article
                                           {
                                               AuthorID = article.AuthorID,
                                               Title = article.Tille,
                                               Body = article.Body
                                           };
                             db.AddToArticles(artc);
                            db.SaveChanges();
                        }
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
             public void DeleteArticle(DTOArticle article)
            {
                var art = new Model.Article { ArticleID = article.ArticleID };
                 using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        db.AttachTo("Articles", art);
                        db.DeleteObject(art);
                        db.SaveChanges();
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }
    }
     The Interface
     
    using System.Collections.Generic;
    using DAL.DTO;
     
    namespace DAL.IDAL
    {
        public interface IArticle
        {
            DTOArticle GetArticle(int id);
            DTOArticle GetArticleTop1();
            List<DTOArticle> GetArticles();
            void UpdateArticles(List<DTOArticle> articles);
            void AddArticles(List<DTOArticle> articles);
            void DeleteArticle(DTOArticle article);
        }
    }
     
    The DTO
     
    amespace DAL.DTO
    {
        public class DTOArticle
        {
            public int ArticleID { get; set; }
            public string Tille { get; set; }
            public string Body { get; set; }
            public int? AuthorID { get; set; }
        }
    }
     
    Monday, May 28, 2012 2:05 PM

All replies

  • Hi Joel Peltonen,

    Welcome to MSDN Forum, I will do more research on this issue and come back as soon as possible. Thanks for your understanding.

    Best Regards


    Allen Li [MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, May 22, 2012 2:24 AM
    Moderator
  • Hi Joel Peltonen,

    Welcome to MSDN Forum.

    I'm afraid I'm not familiar with MVC3, but I found some links may help you. Please refer to them.

    Building an MVC 3 App with Database First and Entity Framework 4.1

    Building an MVC 3 App with Code First and Entity Framework 4.1

    How to use Entity Framework Code First for MVC 3

    About DBContext object lifespan, we often use it in a using statement and create a new instance everytime we need. I hope the links can help. If you need further assistance, please feel free to let me know. I will be more than happy to be of assistance.

    Best Regards


    Allen Li [MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, May 22, 2012 7:39 AM
    Moderator
  •  
    I have never used EF with MVC nor have I used MVC. I use EF with MVP and
    its Presenter and MVVM with WPF and its ViewModel. In either case, I do
    not go after the database in the Presenter or ViewModel with EF or any
    other ADO.NET solution. That's the job of the Data Access Layer.
     
    Tuesday, May 22, 2012 12:26 PM
  • darnold924:

    I'm not really familiar with n-tier apps, MVVM, MVP or WPF. Did I understand you correctly in that you have an architecture where the DAL speaks to the database exclusively? That's kind of what I want to achieve.

    Currently what I do is I have some EF models which contain ALL my db logic using a new dbcontext for everything, like Allen_Li1988 suggested: " we often use it in a using statement and create a new instance everytime we need". My controllers create ViewModels based on the data that EF Models return and pass the VM's to my View engine (Razer). But this seems almost counterproductive as I keep getting the feeling that EF was not designed to work this way - I keep running into lots of problems.

    What I really would like to do is have my DAL/Models as a black box that handles everything database related and spits outs POCO's with very limited logic and a very simple API. I chose EF as the main engine there because it seemed the easiest and fastest to learn but now it seems it's really not as good as I thought at all! I never ever even touch entities, I want to work with non-changetracked data always so it seems that EF really is useless for me? What do you use for your DAL? Do you use entities? I'm getting very lost here.


    • Edited by Joel Peltonen Monday, May 28, 2012 12:32 PM Added text to mar darnold924 as the one I'm responding to.
    Monday, May 28, 2012 12:32 PM
  •  This is a project in a Demo solution I have where the DAL.Article is
    doing everything for the entity Article. It uses the IDAL.Article and
    DTOArticle. The DTO is what is sent through the layers to the viewmodel
    of a WPF UI solution. The EF entity is left at the DAL. The DTO is sent
    back to the DAL to be mapped backed to an entity that is persisted. Of
    course the DAL is being called by the BLL that has an Article object
    that makes the calls.
     
    I would be more than happy to talk to you about the other pieces you
    will need like the Service Layer (I am not talking about a WEB service
    but it can be used with a Web service) and the BLL,
     
     
    using System.Linq;
    using DAL.IDAL;
    using DAL.Model;
    using DAL.DTO;
    using System.Data.EntityClient;
    using System.Collections.Generic;
     namespace DAL
    {
        public class Article :IArticle
        {
            private const string pcdb = "name=PublishingCompanyEntities";
             public DTOArticle GetArticleTop1()
            {
                var dto = new DTOArticle();
                 using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        var article = (from a in db.Articles select
    a).Take(1).First();
                         dto.ArticleID = article.ArticleID;
                        dto.AuthorID =  article.AuthorID;
                        dto.Body = article.Body;
                        dto.Tille = article.Title;
                     }
                    finally
                    {
                        conn.Close();
                    }
                }
                 return dto;
            }
             public DTOArticle GetArticle(int id)
            {
                var dto = new DTOArticle();
                 using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        var article = (from a in db.Articles.Where(a =>
                             a.ArticleID == id)select a).First();
                         dto.ArticleID = article.ArticleID;
                        dto.AuthorID =  article.AuthorID;
                        dto.Body = article.Body;
                        dto.Tille = article.Title;
                     }
                    finally
                    {
                        conn.Close();
                    }
                }
                 return dto;
            }
             public List<DTOArticle> GetArticles()
            {
                var dtos = new List<DTOArticle>();
                 using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        var articles = (from a in db.Articles select
    a).ToList();
                         dtos.AddRange(articles.Select(article => new DTOArticle
                        {
                            ArticleID = article.ArticleID,
                            AuthorID = (int) article.AuthorID,
                            Body = article.Body,
                            Tille = article.Title
                        }));
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
                 return dtos;
            }
             public void UpdateArticles(List<DTOArticle> articles)
            {
                using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        foreach (var article in articles)
                        {
                            var artc = new Model.Article { ArticleID =
    article.ArticleID };
                             db.AttachTo("Articles", artc);
                            artc.AuthorID = article.AuthorID;
                            artc.Title = article.Tille;
                            artc.Body = article.Body;
                            db.SaveChanges();
                        }
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
             public void AddArticles(List<DTOArticle> articles)
            {
                using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        foreach (var article in articles)
                        {
                            var artc = new Model.Article
                                           {
                                               AuthorID = article.AuthorID,
                                               Title = article.Tille,
                                               Body = article.Body
                                           };
                             db.AddToArticles(artc);
                            db.SaveChanges();
                        }
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
             public void DeleteArticle(DTOArticle article)
            {
                var art = new Model.Article { ArticleID = article.ArticleID };
                 using (var conn = new EntityConnection(pcdb))
                using (var db = new PublishingCompanyEntities(conn))
                {
                    try
                    {
                        db.AttachTo("Articles", art);
                        db.DeleteObject(art);
                        db.SaveChanges();
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }
    }
     The Interface
     
    using System.Collections.Generic;
    using DAL.DTO;
     
    namespace DAL.IDAL
    {
        public interface IArticle
        {
            DTOArticle GetArticle(int id);
            DTOArticle GetArticleTop1();
            List<DTOArticle> GetArticles();
            void UpdateArticles(List<DTOArticle> articles);
            void AddArticles(List<DTOArticle> articles);
            void DeleteArticle(DTOArticle article);
        }
    }
     
    The DTO
     
    amespace DAL.DTO
    {
        public class DTOArticle
        {
            public int ArticleID { get; set; }
            public string Tille { get; set; }
            public string Body { get; set; }
            public int? AuthorID { get; set; }
        }
    }
     
    Monday, May 28, 2012 2:05 PM
  • Probably, simplest way would be just use entities as models, like most of tutorials shows. We started with dedicated ViewModels and DTOs in our three-tier solution and now we have bloated VMs code and issues with duplicated validation attributes maintenance.

    Tuesday, May 29, 2012 2:17 PM