locked
Moving from Webforms to MVC - Entity Framework RRS feed

  • Question

  • User423024577 posted

    Hi!

    After more than 10 years of using ASP.NET Webforms absolutely necessary moving to MVC. ASP.NET Webforms was great at the beginning, but now it’s (very) outdated and disadvantages take over... I readed the "Professional ASP.NET MVC 5" (WROX) to learn the basics of MVC. Now there are still some question open...

    In the book and on the internet it is recommended to use the Entity Framework, because it has many advantages (e.g. less code for updating, inserting, and so on). With Webforms I was used to writing my SQL queries myself. The transition from "raw SQL queries" to the Entity Framework is not quite clear to me:

    1. I have an business application where every customer has his own database (the databases are identically for all customers, but every customer has its own database). It's not clear how I can assign a database at runtime to the customer...
    2. As I understand the Entity Frameworks expects an ID field (or a field with a primary key) for updating or deleting an entry. In my existing Webform application not all entries are identified only by the ID / primary key field. For example one customer can have multiple users and I have a table called "settings". In this "settings" table are many options (like sort order, layout settings and so on) for all the users of one customers. The record is identified by the "user_id", a "type" and "option" (e.g. sort order: user_id = 1, type = "grid", option = "sort-order" > for this i will get a "value" (ASC (0), DESC (1)). At my existing Webform-application I do not need an "ID" - because selecting / updating is done with the 3 fields... There also many settings on one page: maybe 10-20 different settings (all settings are different with different type (date, boolean, strings, integers, ...) on one page / layout with a single "save" button. Users press the "save" button, I collect all the different settings (checking for correct inputs) and with 20 updates queries I'm updating the database... My understanding after reading the book: I have to create ONE model with ID, USER_ID, TYPE, OPTION, VALUE (string field) and display it in the view like a table. The user has to request one setting and updates only this single setting - then moving on to the next setting using a new request. Because all settings are different types / controls (checkbox for boolean, date values, textboxes) the automatic check of "ModelState.IsValid" maybe fails... This is where I'm getting in troubles... I'm familiar with the old kind of behaviour in Webforms-Application and my customers also familiar with it. I don't want to create an extra table for every single setting, and I would like to hold the changes small for my customers.

    I don't know how to say: It feels like I'm losing control over database operations... as described above with Webforms I was used to writing my SQL queries myself. Now these thinks are abstracted, which confuses me a little bit. The last days I'm used to search about "use MVC without entity framework". But the overall recommendation is to use the entity framework... at the moment I cannot imagine that I can do everything without using my own SQL queries.

    Especially the questions in point 2 driving me crazy because I can't find an answer to these things... Maybe anyone can remember how his moving from Webforms to MVC has been, and help me out with some recommendations?

    Sunday, June 23, 2019 1:41 PM

Answers

  • User423024577 posted

    Thank you for all your suggestions. Now the things getting clearer to me...

    I think the confusion and my questions are related to the book “Professional ASP.NET MVC 5". It is great, you learn many things and how powerful ASP.NET MVC can be, but they never build an application from scratch to an complete working (sample) application. You start building an application, you also learn how to build the basics. But it starts with the MVC template (were are many features, layouts and so on already included). They start explaining the basics and then they go quickly with detailed explanations without building these things together in the application.

    For example, they explain the DI and IoC and they also show some examples... but I have missed building these parts for a concrete application problem. The same happens with unit testing. Maybe it is not true for others, but for me this book cannot give me the necessary content to build an application by myself.

    Because of that I have bought the book "Pro ASP.NET MVC 5" from Adam Freeman. For me this book is the better choice to learn ASP.NET MVC. After learning the main basics, you start directly building an example application step by step with detailed explanations (including DI, IoC and UnitTests from the beginning).

    I know there is much more to learn, but now all my main questions for this thread are answered and I feel able to start with an own example project.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, July 3, 2019 4:49 PM

All replies

  • User1120430333 posted

    I don't know how to say: It feels like I'm losing control over database operations... as described above with Webforms I was used to writing my SQL queries myself. Now these thinks are abstracted, which confuses me a little bit. The last days I'm used to search about "use MVC without entity framework". But the overall recommendation is to use the entity framework... at the moment I cannot imagine that I can do everything without using my own SQL queries.

    There is nothing saying that you have to use the ADO.NET Entity Framework if you don't want to do so in an ASP.NET MVC project.  You can still use ADO.NET with database command object, parmterized in-line T-SQL or parametrized Stored Procedures in doing CRUD operations with a database.

    You can also use a micro ORM like Dapper where you can still writer your T-SQL yourself or use a sproc.

    https://www.infoworld.com/article/3025784/how-to-work-with-dapper-in-c.html

    To me, a lot of developers don't understand the purpose of using a UI design pattern such as MVC.

    https://www.codeproject.com/Articles/228214/Understanding-Basics-of-UI-Design-Pattern-MVC-MVP

    The 3 UI design patterns can actually be used with Windows desktop or ASP.NET form based solutions if one choose to implement one of UI design pattern, becuase they are just UI design patterns. However, ASP.NET MVC has libraries that supplement its implementation of  the MVC pattern.

    https://www.codeproject.com/Articles/383153/The-Model-View-Controller-MVC-Pattern-with-Csharp

    Some of the JavaScript plugins use the MVC pattern as well, like AngularJs and others.

    You should understand SoC in ASP.NET MVC.

    https://www.c-sharpcorner.com/UploadFile/56fb14/understanding-separation-of-concern-and-Asp-Net-mvc/

    You should understand about  having fat Models, which means having classes in the Models folder that the controller uses keeping the controller skinny as skinny as possible.

    https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/overview/understanding-models-views-and-controllers-cs

    A lot of ASP.NET developers fall into the viewbag rabbit hole. It's not called Viewbag View Controller. It's called Model View Controller. :)

    https://tech.trailmax.info/2013/12/asp-net-mvc-viewbag-is-bad/

    You should understand how to use the viewmodel.

    https://www.c-sharpcorner.com/article/managing-data-with-viewmodel-in-asp-net-mvc/

    You can also look into the Layered architectural style or even n-tier and not have everything in the ASP.NET MVC project like so many developers do

    https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ee658117(v=pandp.10)

    If you're using dataset and datatable, then you might want to use a collection using the DTO pattern for a collection of DTO(s) or a single DTO being used in doing CRUD with the low-level database technology, sending the DTO through the layers. If you use the DTO pattern, the make a classlib project and put the DTO(s) in the classlib project. All projects needing to know about the DTO(s) will have reference to the classlib project and know what the DTO(s) are about..

    https://dzone.com/articles/reasons-move-datatables

    https://www.codeproject.com/articles/1050468/data-transfer-object-design-pattern-in-csharp

    You should try to implement the 'new is glue' principle.

    https://ardalis.com/new-is-glue

    And how you implement the 'the new is glue is by implementing a Interface that allows loose coupling.

    https://www.c-sharpcorner.com/blogs/understanding-interfaces-via-loose-coupling-and-tight-coupling

    By using an Interface for loose coupling, it allows the implantations of an IoC and dependency injection, like using Unity, Autofac Winsdor Castlel  and many other IoC(s).

    https://www.c-sharpcorner.com/UploadFile/cda5ba/dependency-injection-di-and-inversion-of-control-ioc/

    An example ASP.NET Core MVC controller that is using DI via an IoC, which is being used in all the classlib projects, the layers. And if you're going ASP.NET MVC , then go directly to ASP.NET Core MVC and don't look back.

    using System;
    using System.Linq;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.ModelBinding;
    using ProgMgmntCore2UserIdentity.Models;
    
    namespace ProgMgmntCore2UserIdentity.Controllers
    {
        public class TaskController : Controller
        {
            private readonly ITaskModel _taskModel;
            private readonly IProjectModel _projectModel;
            private readonly IModelHelper _modelHelper;
    
            public TaskController(ITaskModel taskModel, IProjectModel projectModel, IModelHelper modelHelper)
            {
                _taskModel = taskModel;
                _projectModel = projectModel;
                _modelHelper = modelHelper;
            }
    
            // GET: Task
            [Authorize]
            public ActionResult Index(int id)
            {
                var project = _projectModel.GetProjectById(id);
    
                TempData["ProjectId"] = id;
                TempData["Title"] = project.ProjectName;
    
                return View(_taskModel.GetTasksByProjectId(id));
            }
    
            [Authorize]
            public ActionResult Details(int id = 0)
            {
                return id == 0 ? null : View(_taskModel.Edit(id));
            }
    
            [Authorize]
            public ActionResult Create()
            {
                return View(_taskModel.Create());
            }
    
            [Authorize]
            [HttpPost]
            public ActionResult Create(TaskViewModels.TaskCreate task, string submit)
            {
                if (submit == "Cancel") return RedirectToAction("Index", new { id = (int)TempData["ProjectId"]});
    
                ValidateddlStatuses();
                ValidateddlDurations();
                ValidateddlResources();
               
                task.Status = (Request.Form["ddlStatusTypes"]);
                task.TaskDuration = (Request.Form["ddlDurations"]);
                task.ResourceId = (Request.Form["ddlResources"]);
    
                if (!ModelState.IsValid) return View((TaskViewModels.TaskCreate)_taskModel.PopulateDropDownLists(task, "Create"));
    
                _taskModel.Create(task, (int)TempData["ProjectId"]);
                return RedirectToAction("Index", new { id = (int)TempData["ProjectId"] });
            }
    
            [Authorize]
            public ActionResult Edit(int id = 0)
            {
                return id == 0 ? null : View(_taskModel.Edit(id));
            }
    
            [Authorize]
            [HttpPost]
            public ActionResult Edit(TaskViewModels.TaskEdit task, string submit)
            {
                if (submit == "Cancel") return RedirectToAction("Index", new { id = (int)TempData["ProjectId"]});
    
                if (ModelState.IsValid && _modelHelper.IsEndDateLessThanStartDate(task, "Task"))
                {
                    ModelState.AddModelError(String.Empty, "End Date cannot be less than Start Date.");
                }
    
                if (!ModelState.IsValid) return View( (TaskViewModels.TaskEdit)_taskModel.PopulateDropDownLists(task, "Edit"));
    
                var thetask = new TaskViewModels.TaskEdit();
    
                thetask = task;
    
                thetask.ProjectId = (int) TempData["ProjectId"];
    
                _taskModel.Edit(thetask);
                return RedirectToAction("Index", new { id = (int)TempData["ProjectId"]});
            }
    
            public ActionResult Delete(int id = 0)
            {
                if (id > 0) _taskModel.Delete(id);
    
                return RedirectToAction("Index", new { id = (int)TempData["ProjectId"] });
            }
    
            public ActionResult Cancel()
            {
                var id = TempData["ProjectId"];
    
                return RedirectToAction("Index", "Home");
            }
    
            public ActionResult UploadFile(int id)
            {
                return RedirectToAction("Index", "Upload", new { id = id, type = "TM" });
            }
    
            private void ValidateddlStatuses()
            {
                if (Request.Form["ddlStatusTypes"] == string.Empty)
                   return;
    
                foreach (var key in ModelState.Keys.ToList().Where(key => ModelState.ContainsKey(key)))
                {
                    if (key != "Status") continue;
                    ModelState[key].Errors.Clear();
                    ModelState[key].ValidationState = ModelValidationState.Valid;
                }
            }
    
            private void ValidateddlDurations()
            {
                if (Request.Form["ddlDurations"] == string.Empty)
                   return;
    
                foreach (var key in ModelState.Keys.ToList().Where(key => ModelState.ContainsKey(key)))
                {
                    if (key != "TaskDuration") continue;
                    ModelState[key].Errors.Clear();
                    ModelState[key].ValidationState = ModelValidationState.Valid;
                }
            }
    
            private void ValidateddlResources()
            {
                if (Request.Form["ddlResources"] == string.Empty)
                   return;
                
                foreach (var key in ModelState.Keys.ToList().Where(key => ModelState.ContainsKey(key)))
                {
                    if (key != "ResourceId") continue;
                    ModelState[key].Errors.Clear();
                    ModelState[key].ValidationState = ModelValidationState.Valid;
                }
            }
        }
    }

    Sunday, June 23, 2019 3:38 PM
  • User1120430333 posted

    I have an business application where every customer has his own database (the databases are identically for all customers, but every customer has its own database). It's not clear how I can assign a database at runtime to the customer...

    I forgot about the above.

    https://en.wikipedia.org/wiki/Multitenancy

    https://www.codingame.com/playgrounds/5440/multi-tenant-asp-net-core-2---implementing-database-based-tenant-provider

    In the below thread is about getting the connectionstring dynamically in a EF Dbcontext or by other means.

    https://forums.asp.net/t/2156522.aspx?Manually+setting+connection+string+of+DbContext+in+a+scope+in+a+SignalR+Core+hub

    https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/areas?view=aspnetcore-2.2

    Sunday, June 23, 2019 4:06 PM
  • User475983607 posted

    Entity framework is an object oriented interlace to a database. If you want to implement EF, there are constraints.  You must weigh these constraints against your application requirements to determine if EF is an acceptable data access solution.

    at the moment I cannot imagine that I can do everything without using my own SQL queries.

    Entity framework allows for executing raw queries.

    https://docs.microsoft.com/en-us/ef/ef6/querying/raw-sql

    Especially the questions in point 2 driving me crazy because I can't find an answer to these things... Maybe anyone can remember how his moving from Webforms to MVC has been, and help me out with some recommendations?

    You misunderstand the technology.  MVC does not dictate the use of Entity Framework.   It's up to you to determine if EF is a good fit for your application.  Plus you are confusing MVC Models with Entities in EF.

    FYI, the biggest issue you are facing is number 1 because EF it expected a consistent DB schema.   If the databases have different schema the you'll need a DbContext for each database.

    Number 2, Entity Framework requires a primary key not an ID field.  The primary key can be made up of several fields.  Anyway, raw queries let you get around handling tables that do not have primary keys.  

    Sunday, June 23, 2019 4:36 PM
  • User1520731567 posted

    Hi Phoniex,

    I don't know how to say: It feels like I'm losing control over database operations...

    Using MVC won't let you lose control of SQL.

    There are many ways to control the database.

    You could use linq ,Raw SQL Queries ,ADO.NET or call store produce in above methods and so on...

    For example: select in Raw SQL(more details from this link)

    public ActionResult About()
    {
        //Commenting out LINQ to show how to do the same thing in SQL.
        //IQueryable<EnrollmentDateGroup> = from student in db.Students
        //           group student by student.EnrollmentDate into dateGroup
        //           select new EnrollmentDateGroup()
        //           {
        //               EnrollmentDate = dateGroup.Key,
        //               StudentCount = dateGroup.Count()
        //           };
    
        // SQL version of the above LINQ code.
        string query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
            + "FROM Person "
            + "WHERE Discriminator = 'Student' "
            + "GROUP BY EnrollmentDate";
        IEnumerable<EnrollmentDateGroup> data = db.Database.SqlQuery<EnrollmentDateGroup>(query);
    
        return View(data.ToList());
    }

    In addidtion,you could even give up EF, you can use other frameworks, such as: ibatis...

    Best Regards.

    Yuki Tao

    Monday, June 24, 2019 3:08 AM
  • User423024577 posted

    Thank you for all your suggestions. Now the things getting clearer to me...

    I think the confusion and my questions are related to the book “Professional ASP.NET MVC 5". It is great, you learn many things and how powerful ASP.NET MVC can be, but they never build an application from scratch to an complete working (sample) application. You start building an application, you also learn how to build the basics. But it starts with the MVC template (were are many features, layouts and so on already included). They start explaining the basics and then they go quickly with detailed explanations without building these things together in the application.

    For example, they explain the DI and IoC and they also show some examples... but I have missed building these parts for a concrete application problem. The same happens with unit testing. Maybe it is not true for others, but for me this book cannot give me the necessary content to build an application by myself.

    Because of that I have bought the book "Pro ASP.NET MVC 5" from Adam Freeman. For me this book is the better choice to learn ASP.NET MVC. After learning the main basics, you start directly building an example application step by step with detailed explanations (including DI, IoC and UnitTests from the beginning).

    I know there is much more to learn, but now all my main questions for this thread are answered and I feel able to start with an own example project.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, July 3, 2019 4:49 PM