2020년 11월 12일 목요일

C# ASP.NET - Multiple Models in a View in ASP.NET MVC


https://www.codeproject.com/Articles/687061/Multiple-Models-in-a-View-in-ASP-NET-MVC-MVC

 

Introduction

When I was a beginner for ASP.NET MVC, I faced a question many times: how many ways do you know to use/pass multiple models in/to a view? At that time, I knew only two ways, then I learned some other ways to achieve the same. In this article, I will share my learning so far. Hope it will be helpful for others.

Pre-requisite: you should be at intermediate level with C# and ASP.NET MVC. If you are absolute new to C# and ASP.NET MVC, please look for other resources to understand terms used here. You can put comment below article in case you need any detail. I will be happy to help. Thanks.

There are many ways of using multiple models in a view, most frequently used are given below:

  • ViewData
  • ViewBag
  • PartialView
  • TempData
  • ViewModel
  • Tuple

All the above ways of using multiple models in view have their place but we need to think and pick which one fits our requirements. All techniques have their own advantages and disadvantages and we have such discussion in another article How to Choose the Best Way to Pass Multiple Models.

To understand the article better, please download the attached code, have an overview of the code, then follow the steps given in this article.

Overview of Sample Demo

The attached code solution has six views demonstrating the following:

  • How to pass multiple models using ViewData
  • How to pass multiple models using ViewBag
  • How to pass multiple models using PartialView
  • How to pass multiple models using TempData
  • How to pass multiple models using ViewModel
  • How to pass multiple models using Tuple

In the sample demo, all views will have similar HTML structure to get same layout but implementation to pass models to the view will be different.

Structure of the HTML tags is shown below only code inside the scripts tag will be changed as per the scenarios.


Output of all demos will be similar to the screenshot shown below:


Creating Basic Structure of Sample Demo

Let's get started by creating a sample demo application. Follow the below steps:

  1. Open Visual Studio 2012, select ASP.NET MVC4 Web Application template and give it project name as MultipleModelDemo and click OK. If you are using Visual Studio 2013 and MVC 5, Please look into the Update for VS 2013 / MVC 5 section below.


  2. Select a template as Basic application then click OK. Visual Studio adds a MultipleModelDemo project in solution as shown below in screenshot.


  3. Right click on the Models folder, add a Models.cs file. Now we need to add three models named as Course, Faculty and Student by writing the following code as shown below:
    public class Course
    {
        public int CourseId { get; set; }
        public string CourseName { get; set; }
    }
    
    public class Faculty
    {
        public int FacultyId { get; set; }
        public string FacultyName { get; set; }
        public List<Course> AllotedCourses { get; set; }
    }
    
    public class Student
    {
        public int EnrollmentNo { get; set; }
        public string StudentName { get; set; }
        public List<Course> EnrolledCourses { get; set; }
    }
  4. Add a class file under the Models folder named as Repository.cs file, which will have the implementation of methods to get hardcoded data for application in order to keep it convenient.

    Following is the code for GetCourse method which will return a list of courses:

    public List<Course> GetCourses()
    {
        return new List<Course> { 
            new Course () {  CourseId = 1, CourseName = "Chemistry"}, 
            new Course () {  CourseId = 2, CourseName = "Physics"},
            new Course () {  CourseId = 3, CourseName = "Math" },
            new Course () {  CourseId = 4, CourseName = "Computer Science" }
        };
    }           

    Following is the code GetFaculties method which will return a list of faculties:

    public List<Faculty> GetFaculties()
    {
        return new List<Faculty> {                 
            new Faculty () {  FacultyId = 1, FacultyName= "Prakash",
                AllotedCourses = new List<Course> 
                {new Course () { CourseId = 1, CourseName = "Chemistry"},
                                 new Course () { CourseId = 2, CourseName = "Physics"},
                                 new Course () { CourseId = 3, CourseName = "Math"},
            }}, 
            new Faculty () {  FacultyId = 2, FacultyName= "Ponty" ,
                AllotedCourses = new List<Course> 
                {new Course () { CourseId = 2, CourseName = "Physics"},
                                 new Course () { CourseId = 4, CourseName = "Computer Science"}
            }},
            new Faculty () {  FacultyId = 3, FacultyName= "Methu", 
                AllotedCourses = new List<Course> 
                {new Course () { CourseId = 3, CourseName = "Math"},
                                 new Course () { CourseId = 4, CourseName = "Computer Science"}
            }}
        };
    }           

    Following is the code for GetStudents method which will return a list of students:

    public List<Student> GetStudents()
    {
        List<Student> result = new List<Student> { 
            new Student () { EnrollmentNo = 1, StudentName= "Jim", 
                EnrolledCourses = new List<Course> 
                { new Course () { CourseId = 1, CourseName = "Chemistry"},
                                  new Course () { CourseId = 2, CourseName = "Physics"},
                                  new Course () { CourseId = 4, CourseName = "Computer Science"}
            }},
            
            new Student () {  EnrollmentNo = 2, StudentName= "Joli",
                EnrolledCourses = new List<Course> 
                { new Course () { CourseId = 2, CourseName = "Physics"} ,
                                  new Course () 
                                  { CourseId = 4, CourseName = "Computer Science"}
            }},
            
            new Student () {  EnrollmentNo = 3, StudentName= "Mortin",
                EnrolledCourses = new List<Course>
                {  new Course () { CourseId = 3, CourseName = "Math"},
                                   new Course () { CourseId = 4, CourseName = "Computer Science"}
            }}
        };
        
        return result;
    }           
  5. Add a HomeController to Controller folder. We will write the code in HomeController later.
     
  6. In Shared folder, we will modify the existing code in _Layout.cshtml file. First write the following code in head tag:
     <head>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width" />
    
    @*Referenced  js and css files which comes with template*@
     <script src="~/Scripts/jquery-1.8.2.min.js"></script>
     <link href="~/Content/Site.css" rel="stylesheet" />
    
     @*Referenced appcss file having custom CSS*@
     <link href="~/Content/appcss/appcss.css" rel="stylesheet" />
     </head>
    

    Write the following code in body tag:

    <body>
        @* Define the place for navigation links in left side of the page*@
        <div class="navigationPanel">
            <div style="margin: 40px 25px 2px 25px;">
                <h3>Links to Demostrations</h3>
                <a href="~/Home/ViewDataDemo">ViewData Demo</a>
                <br />
                <br />
                <a href="~/Home/ViewBagDemo">ViewBag Demo</a>
                <br />
                <br />
                <a href="~/Home/PartialViewDemo">PartialView Demo</a>
                <br />
                <br />
                <a href="~/Home/TempDataDemo">TempData Demo</a>
                <br />
                <br />
                <a href="~/Home/ViewModelDemo">ViewModel Demo</a>
                <br />
                <br />
                <a href="~/Home/TupleDemo">Tuple Demo</a>
            </div>
        </div>
        <div style="float: left; margin: 25px 2px 2px 80px;">
            @RenderBody()
        </div>
    </body>

    So far, we have created basic code which we will be using in all scenarios. Further, we will learn each scenario one by one.

Passing Multiple Models using ViewData

ViewData is used to pass data from a controller to a view. ViewData is a dictionary of objects that is a type of ViewDataDictionary class. ViewData is defined as property in ControllerBase class. Values stored in ViewData require typecasting to their datatype in view. The values in ViewData are accessible using a key.

  1. First, create a object of Repository class in HomeController.
    Repository _repository = new Repository();             

    Add the following code in HomeController.

    public ActionResult ViewDataDemo()
    {
        ViewData["Courses"] = _repository.GetCourses();
        ViewData["Students"] = _repository.GetStudents();
        ViewData["Faculties"] = _repository.GetFaculties();
        return View();
    }           

    Here ViewDataDemo action method will be passing all three models to its view using ViewData.

  2. Add a view named as ViewDataDemo and write the same code as written below in body tag.
    <body style="background-color: #DBDBB7">
     <h3>Passing Multiple Models using <span class="
     specialText">  <i>ViewData </i> </span> </h3>
     <table>
         <tr>
             <td class="sltCourseText">
                 <h3>Select a Course  </h3>
             </td>
             <td>
                 <select id="sltCourse" class="sltStyle">
                    <option>Select Course </option>
                    @*Iterating Course model using ViewData string as a key *@
                    @foreach (var item in ViewData["Courses"] 
                    as List <MultipleModelDemo.Models.Course>)
                    {         
                         <option>@item.CourseName
                         </option>            
                    }
                 </select>
             </td>
         </tr>
     </table>
         
     <div id="facultyDetailSection">
         <h4>Faculties who teach selected course </h4>
         <div id="facultyDetailTable"> </div>
     </div>
         
     <div id="studentDetailSection">
         <h4>Students who learn selected course </h4>
         <div id="studentDetailTable"> </div>
     </div>
     </body>        

    Here we are iterating Course model using ViewData and casting it into a List<Course>.

  3. Inside the body tag, add a script tag and write the following code. Here we would show the table only when user will select a valid course otherwise the facultyDetailSection and studentDetailSection should not be appearing. We are using fadeout and fadeIn function of jQuery for that purpose.
    <script>
           $(document).ready(function(){
               $("#facultyDetailSection").fadeOut(0);
               $("#studentDetailSection").fadeOut(0);
           });
    
           var selectedCourseName;
    
           $("#sltCourse").change(function () {
               selectedCourseName = $("#sltCourse").val().trim();
    
               if (selectedCourseName === "Select Course") {
                   $("#facultyDetailSection").fadeOut();
                   $("#studentDetailSection").fadeOut();
               }
               else {
                   getFacultyTable();
                   getStudentTable();
                   $("#facultyDetailSection").fadeIn();
                   $("#studentDetailSection").fadeIn();
               }
           });
    </script>
    

    Here on the change event of Course dropdown, we will read the value and confirm if there is a valid selection to display faculties and students. In case of a valid selection, getFacultyTable and getStudentTable function will be executed. Add the following functions in script tag:

        //Create table to display faculty detail
        function getFacultyTable() {         
        $("#facultyDetailTable").empty();
        $("#facultyDetailTable").append("<table id='tblfaculty'  
        class='tableStyle'><tr><th class='tableHeader' style='width:60px;'>
                                            Employee ID </th> 
                                            <th class='tableHeader'>Faculty Name 
                                            </th> </tr> </table>");
    
        //Get all faculties with the help of model 
        //(ViewData["Faculties"]), and convert data into json format. 
        var allFaculties = @Html.Raw(Json.Encode(ViewData["Faculties"]));
    
        for (var i = 0; i  < allFaculties.length; i++) {
            var allotedCourses = allFaculties[i].AllotedCourses;
            for (var j = 0; j  < allotedCourses.length; j++) {
                if(allotedCourses[j].CourseName === selectedCourseName)
                    $("#tblfaculty").append
                    (" <tr> <td class='tableCell'>"  + 
                    allFaculties[i].FacultyId 
                        + " </td> <td class='tableCell'>"+
                        allFaculties[i].FacultyName+" </td> </tr>");
            }
        }
    }
    
    //Create table to display student detail
    function getStudentTable() {
        $("#studentDetailTable").empty();
        $("#studentDetailTable").append(" <table id='tblStudent' 
        class='tableStyle'> <tr> <th class='tableHeader' style='width:60px;'>
                                            Roll No </th> <th 
                                            class='tableHeader'>Student Name 
                                            </th> </tr> </table>");
    
        //Get all students with the help of model 
        //(ViewData["Students"]), and convert data into json format. 
        var allStudents = @Html.Raw(Json.Encode(ViewData["Students"]));
    
        for (var i = 0; i  < allStudents.length; i++) {
            var studentCourses = allStudents[i].EnrolledCourses;
            for (var j = 0; j  < studentCourses.length; j++) {
                if(studentCourses[j].CourseName === selectedCourseName)                      
                    $("#tblStudent").append(" <tr> 
                    <td class='tableCell'>"  + allStudents[i].EnrollmentNo 
                        + " </td> <td  class='tableCell'>
                        "+allStudents[i].StudentName+" </td> </tr>");
            }
        }           
    }            

Note: As we have mentioned, all view will have same layout so further demos will have almost the same code as you have written in body tag of ViewDataDemo.cshtml file, now in further demos we just need to modify foreach function to fill data in dropdown and two lines of code in getFacultyTable and getStudentTable JavaScript function.

Passing Multiple Models using ViewBag

ViewBag is also used to pass data from a controller to a view. It is a dynamic property which comes in ControllerBase class that is why it doesn’t require typecasting for datatype.

  1. Add the following code in HomeController:
    public ActionResult ViewBagDemo()
    {
        ViewBag.Courses = _repository.GetCourses();
        ViewBag.Students = _repository.GetStudents();
        ViewBag.Faculties = _repository.GetFaculties();
        return View();
    }            

    Here ViewBagDemo action method will be passing data to view (ViewBagDemo.cshtml) file using ViewBag.

  2. Add a view named as ViewBagDemo. All code will be same as you have written in ViewDataDemo.cshtml file. Just modify input model to foreach function.
    @*Iterating Course model using ViewBag *@
    @foreach (var item in ViewBag.Courses)
    {         
        <option>@item.CourseName</option>            
    }            
  3. In script tag, replace the following line of code in getFacultyTable function:
    //Get all faculties with the help of model 
    // (ViewBag.Faculties), and convert data into json format.                
    var allFaculties = @Html.Raw(Json.Encode(ViewBag.Faculties));
  4. Replace the following line of code in getStudentTable function:
    //Get all students with the help of model(ViewBag.Students), 
    //and convert data into json format.
    var allStudents = @Html.Raw(Json.Encode(ViewBag.Students));

Passing Multiple Models using PartialView

Partial view is used where you need to share the same code (Razor and HTML code) in more than one view. For more details about PartialView, please visit here.

  1. In Home controller, add the following code, PartialViewDemo action method will return a view having the list of all courses only. This action method will not have or pass any faculty or student information as of now.
    public ActionResult PartialViewDemo()
    {
        List<Course> allCourse = _repository.GetCourses();
        return View(allCourse);
    }            
  2. Add a view named as PartialViewDemo. All HTML code will be same as you have written before. Just modify foreach function.
    @*Iterating Course Model*@
    @foreach(var item in Model)
    {         
        <option>@item.CourseName
        </option>            
    }            
  3. In script tag, modify getFacultyTable function as written below:
    function getFacultyTable() {
    		$.ajax({
    	        // Get Faculty PartialView
    	        url: "/Home/FacultiesToPVDemo",
    	    type: 'Get',
    	    data: { courseName: selectedCourseName },
    	    success: function (data) {
            $("#facultyDetailTable").empty().append(data);
    	    },
    	    error: function () {
            alert("something seems wrong");
    	}
    		});
    }
  4. Modify getStudentTable function as written below:
        function getStudentTable() {
        $.ajax({
            // Get Student PartialView
            url: "/Home/StudentsToPVDemo",
            type: 'Get',
            data: { courseName: selectedCourseName },
            success: function (data) {
                $("#studentDetailTable").empty().append(data);
            },
            error: function () {
                alert("something seems wrong");
            }
        });
    }        
  5. Add a new Action method in HomeController as StudentsToPVDemo and add the following code in StudentsToPVDemo action method.
    public ActionResult StudentsToPVDemo(string courseName)
    {
        IEnumerable <Course> allCourses = _repository.GetCourses();
        var selectedCourseId = (from c in allCourses where 
        c.CourseName == courseName select c.CourseId).FirstOrDefault();
        
        IEnumerable <Student> allStudents = _repository.GetStudents();
        var studentsInCourse = allStudents.Where(s => 
        s.EnrolledCourses.Any(c => c.CourseId == selectedCourseId)).ToList();
        
        return PartialView("StudentPV", studentsInCourse); 
    }
  6. Add a PartialView to the Shared folder by right clicking on StudentsToPVDemo action method, give it name as StudentPV. StudentsToPVDemo action will return StudentPV PartialView having the list of students studying in a particular course.

  7. Add the following code in StudentPV.cshtml file.
    @model  IEnumerable <MultipleModelDemo.Models.Student>
     <table id="tblFacultyDetail" class="tableStyle">
             <tr>
             <th class="tableHeader" style="width:60px;">Roll No </th>
             <th class="tableHeader">Student Name </th>
             </tr>
        @foreach (var item in Model)
        {
              <tr>
                 <td  class="tableCell" >@item.EnrollmentNo </td>
                 <td class="tableCell">@item.StudentName </td>
             </tr>
        }       
     </table>
  8. Add a new action method to call PatialView for faculties in HomeController. Name it as FacultiesToPVDemo and add the following code:
    public ActionResult FacultiesToPVDemo(string courseName)
    {
        IEnumerable <Course> allCourses = _repository.GetCourses();
        var selectedCourseId = (from c in allCourses where 
        c.CourseName == courseName select c.CourseId).FirstOrDefault();
        
        IEnumerable <Faculty> allFaculties = _repository.GetFaculties();
        var facultiesForCourse = allFaculties.Where(f => 
        f.AllotedCourses.Any(c =>  c.CourseId == selectedCourseId)).ToList();
        
        return PartialView("FacultyPV", facultiesForCourse);
      }            
  9. Add a PartialView named as FacultyPV as we did for student PartialView, write the same code as you have written in StudentPV.cshtml file. Just replace one line of code as:
    @model  IEnumerable<MultipleModelDemo.Models.Faculty>
  10. FacultiesToPVDemo action will return FacultyPV PartialView having the list of faculties who teach a particular course.

Passing Multiple Models using TempData

TempData is a dictionary of objects that is a type of TempDataDictionary class. TempData is defined as property in ControllerBase class. Values stored in TempData require typecasting to datatype in view. The values in TempData are accessible using a key. It is similar to ViewData but the difference is that it allow us to send and receive the data from one controller to another controller and from one action to another action. It’s all about possible because it internally uses session variables.

For more information about TempData, please visit here. Here, we will use TempData only to hold (at server side HomeController) and pass (to the TempDataDemo.cshtml) List of Courses.

  1. In home controller, add the following code:
    public ActionResult TempDataDemo()
    {
        // TempData demo uses repository to get List<courses> only one time
        // for subsequent request to get List<courses> it will use TempData
        TempData["Courses"] = _repository.GetCourses();
    
        // This will keep Courses data untill next request is served
        TempData.Keep("Courses");
        return View();
    }
  2. Using TempData, we can pass values from one action to another action. TempData["Courses"] having the list of course. We will access this list in FacultiesToTempDataDemo action as shown below:
    public ActionResult FacultiesToTempDataDemo(string courseName)
    {
        var allCourses = TempData["Courses"] as IEnumerable <Course>;
        
        // Since there are two AJAX call on TempDataPage
        // So we keep to keep Courses data for the next one
        TempData.Keep("Courses");
        var selectedCourseId = (from c in allCourses where 
        c.CourseName == courseName select c.CourseId).FirstOrDefault();
        
        IEnumerable <Faculty> allFaculties = _repository.GetFaculties();
        var facultiesForCourse = allFaculties.Where(f => 
        f.AllotedCourses.Any(c => c.CourseId == selectedCourseId)).ToList();
        
        return PartialView("FacultyPV", facultiesForCourse);
    }
    
    public ActionResult StudentsToTempDataDemo(string courseName)
    {
        var allCourses = TempData["Courses"] as IEnumerable <Course>;
        
        // If there is change in course again...it may cause more AJAX calls
        // So we need to keep Courses data
        TempData.Keep("Courses");
        
         var selectedCourseId = (from c in allCourses where 
         c.CourseName == courseName select c.CourseId).FirstOrDefault();
         
        IEnumerable <Student> allStudents = _repository.GetStudents();
        var studentsInCourse = allStudents.Where(s => 
        s.EnrolledCourses.Any(c => c.CourseId == selectedCourseId)).ToList();
        
        return PartialView("StudentPV", studentsInCourse);
    }            
  3. Add a view by right clicking on TempDataDemo action method. Write the same code as you have written in PartialViewDemo.cshtml. Only one line of code needs to modify as written below:
    @*Iterating Course model using TempData["Courses"] *@
    @foreach (var item in TempData["Courses"] 
    	as List <MultipleModelDemo.Models.Course>)
    {         
        <option>@item.CourseName </option>            
    }           

    Modify url in getFacultyTable and getStudentTable function respectively as written below:

    url: "/Home/FacultiesToTempDataDemo",
    url: "/Home/StudentsToTempDataDemo",            

    Both Action methods FacultiesToTempDataDemo and StudentsToTempDataDemo will return the same PartialView which we used for PartialView demo.

Passing Multiple Models using ViewModel

ViewModel is a pattern that allow us to have multiple models as a single class. It contains properties of entities exactly need to be used in a view. ViewModel should not have methods. It should be a collection of properties needed for a view.

  1. We have three models (classes) named as Student, Course and Faculty. All are different models but we need to use all three models in a view. We will create a ViewModel by adding a new folder called ViewModels and add a class file called ViewModelDemoVM.cs and write the following code as shown below:
    public class ViewModelDemoVM
    {        
        public List <Course> allCourses { get; set; }
        public List <Student> allStudents { get; set; }
        public List <Faculty> allFaculties { get; set; }
    }            

    Note: As a good practice when you create any ViewModel, it should have suffix as VM or ViewModel.

  2. In the HomeController, add the following code:
    public ActionResult ViewModelDemo()
    {
        ViewModelDemoVM vm = new ViewModelDemoVM();
        vm.allCourses = _repository.GetCourses();
        vm.allFaculties = _repository.GetFaculties();
        vm.allStudents = _repository.GetStudents();
    
        return View(vm);
    }            

    ViewModelDemo is an action method that will return a view having ViewModelDemoVM which has lists of all Courses, Faculties and Students.

  3. Right click on ViewModelDemo to add a view is called ViewModelDemo. ViewModelDemo.cshtml view will use ViewModelDemoVM as Model as shown below:
    @model MultipleModelDemo.ViewModel.ViewModelDemoVM            
  4. Modify foreach function.
    @*Iterating Course ViewModel *@
    @foreach (var item in Model.allCourses)
        {         
            <option>@item.CourseName</option>            
        }            
  5. Replace the following line of code in getFacultyTable function:
    //Get all faculties with the help of viewmodel
    //(Model.allFaculties), and convert data into json format.
    var allFaculties = @Html.Raw(Json.Encode(Model.allFaculties));
  6. Replace the following line of code in getStudentTable function:
    //Get all students with the help of viewmodel(Model.allStudents), 
    //and convert data into json format.
    var allStudents = @Html.Raw(Json.Encode(Model.allStudents));            

Passing Multiple Models using Tuple

Tuple is a new class introduced in .NET Framework 4.0. It is an ordered sequence, immutable, fixed-size collection of heterogeneous (allows us to group multiple kind of data types) objects.

  1. Add the following code in Home controller.
    public ActionResult TupleDemo()
    {
        var allModels = new Tuple <List <Course>, 
        List <Faculty>,  List <Student>>
        (_repository.GetCourses(), _repository.GetFaculties(),  _repository.GetStudents()) { };
         return View(allModels);
    }            

    Here, we are defining a tuple which is having lists of courses, faculties and students. We are passing this tuple to the View.

  2. Add a View named as TupleDemo. Write code as you have written in ViewModelDemo.cshtml file. Just need to replace few lines of code. Replace model declarations as shown below. Here, we will use the namespace used to avoid long fully qualified class names.
    @using MultipleModelDemo.Models;
    @model Tuple <List <Course>, List <Faculty>, List <Student>>            
  3. Modify foreach function:
    @*Iterating Course model using tuple *@
    @foreach (var item in Model.Item1)
        {         
             <option>@item.CourseName </option>            
        }            

    Here Model.Item1 is mapped to Course model.

  4. Inside the JavaScript function called getFacultyTable replace the following line of code:
    var allFaculties = @Html.Raw(Json.Encode(Model.Item2));            

    Here Model.Item2 is mapped with Faculty model.

  5. Inside the JavaScript function called getStudentTable, replace the following line of code:
    var allStudents = @Html.Raw(Json.Encode(Model.Item3));            

    Here Model.Item3 is mapped with Student model.

Update for VS 2013 / MVC 5

If you would like to use Visual Studio 2013 / MVC 5, Step 1 and 2 as given for MVC 4 would be different, So please follow the steps as given below and then start from steps 3 as given for MVC 4 above.

  1. Open Visual Studio 2013, Click on "New Project" and select ASP.NET Web Application template and give it project name as MultipleModelDemo and click OK.


  2. Select a template as MVC and make sure that all check box given in lower section of popup are unchecked other than MVC. Before clicking OK, we need to change Authentication (since for this demo we are not using either Authentication or Unit Tests to keep it simple and to the point). Please find screen shots below for the same:



    Changing the Authentication from "Individual User Account" to "No Authentication":



    Visual Studio adds a MultipleModelDemo project in solution. Now you can follow the step 3 and further as given for MVC 4.

Conclusion

In this article, we learned how to use multiple models in a view. In the article How to Choose the Best Way to Pass Multiple Models, I have shared my findings about when and where to pick a particular way to use multiple models in a view. Your inputs and queries are most welcome. Thanks.


2020년 11월 10일 화요일

javascript - json date array filter


json 객체내에서 조건에 맞는 값을 찾거나 유효한 데이터만을 추출 

<script type="text/javascript">
(function test(){
    var testJson = [{name : "이건", salary : 50000000},
                    {name : "홍길동", salary : 1000000},
                    {name : "임신구", salary : 3000000},
                    {name : "이승룡", salary : 2000000}];
    
    var newJson = testJson.filter(function(element){
        console.log(element);
        return element.name == "이건";
    });
    console.log("newObj");
    console.log(newJson);
})(); 
</script>



json 데이터의 유효성 검증에도 활용

<script type="text/javascript">
(function test(){
    var testJson = [{name : "이건", salary : 50000000},
                    {name : "홍길동", salary : 1000000},
                    {name : "임신구", salary : 3000000},
                    {name : "이승룡", salary : 2000000},
                    {},
                    {name : "이철수", salary : NaN},
                    {name : "이재춘", salary : 'undefined'},
                    {name : "이제일", salary : -2000000}];
 
    function numberFilter(obj){
        if ('salary' in obj && (typeof(obj.salary)==='number') && !isNaN(obj.salary) && obj.salary>0){
            return true;
        }else{
            return false;
        }
    }
    var newJson = testJson.filter(numberFilter);
    console.log("newObj");
    console.log(newJson);
})(); 
</script>


2020년 11월 2일 월요일

ASP - 에러 메세지 모음


---------------------------------------------------------------------------------

Microsoft VBScript 런타임 오류 error '800a01a8' 

개체가 필요합니다.: 에러내용

/파일명.asp, line 에러라인번호
 

- 개체이름이 잘못되었을 경우 (option explicit 상태일때는 '변수가 정의되지 않았습니다')
Ex)  resopnse.write  "test" 

---------------------------------------------------------------------------------

Microsoft VBScript 런타임 오류 error '800a000d' 

형식이 일치하지 않습니다.: 에러내용

/파일명.asp, line 에러라인번호 


- 알 수 없는 함수
- 알 수 없는 명령어
- 소스 중간에 임의의 문자가 들어간 경우 
- 데이터형식이 잘못됨(Ex. 매개변수에 배열이 들어가야하는데 배열이 아닌 변수가 들어감)
- 함수가 아닌 서브로 리턴값을 받으려 할때

---------------------------------------------------------------------------------

Microsoft VBScript 런타임 오류 error '800a01f4'  

변수가 정의되지 않았습니다.: 변수명

/파일명.asp, line 에러라인번호


- 알 수 없는 명령어, 소스 중간에 임의의 문자가 들어간 경우, 변수선언이 안되어있을때(option explicit 상태일때)

---------------------------------------------------------------------------------

Microsoft VBScript 컴파일 오류 error '800a0400' 

문장이 필요합니다. 

/파일명.asp, line 에러라인번호

에러소스내용


- 소스중간에 숫자가 변수나 서브처럼 사용되었을 경우

---------------------------------------------------------------------------------

Microsoft VBScript 런타임 오류 error '800a01c2' 

인수의 개수나 속성 할당이 잘못되었습니다.: 함수명 or 서브명

/파일명.asp, line 에러라인번호


- 함수나 서브의 매개변수 갯수가 다름

---------------------------------------------------------------------------------

Microsoft VBScript 컴파일 오류 error '800a0414' 

Sub를 호출할 때는 괄호를 사용할 수 없습니다. 

/파일명.asp, line 에러라인번호

에러소스내용


- 함수를 리턴값을 받지 않고 사용하거나 서브를 call 없이 단독으로 사용하였을 경우

---------------------------------------------------------------------------------

Microsoft VBScript 컴파일 오류 error '800a0408' 

유효하지 않은 문자입니다. 

/파일명.asp, line 에러라인번호

에러소스내용


- 소스 중간에 한글, 한문,  특수문자 등이 들어갔을 경우

---------------------------------------------------------------------------------

Microsoft VBScript 런타임 오류 error '800a01b6' 

개체가 이 속성 또는 메서드를 지원하지 않습니다.: 해당개채 

/파일명.asp, line 에러라인번호


- 해당개체의 잘못된(없는) 메서드나 속성을 사용하려할때

Ex)
response.wtite "test"
response.write request.servervariable("REMOTE_ADDR")


- set 없이 변수에 리턴값이 오브젝트인 것을 넣으려할때
Ex) mail = Server.CreateObject("CDO.Message")      =&gt;    set mail = Server.CreateObject("CDO.Message")

---------------------------------------------------------------------------------

서버 개체 error 'ASP 0177 : 800401f3' 

Server.CreateObject 실패 

/파일명.asp, line 에러라인번호

잘못된 프로그램 ID입니다. 이 메시지에 대한 추가 정보를 보려면 다음 Microsoft 온라인 지원 사이트를 방문하십시오: http://www.microsoft.com/contentredirect.asp. 


- Server.CreateObject 로 알수없는 서버개체를 생성하려 할때
  (Ex. Windows 2000 Server 가 아닌 서버에서  Server.CreateObject("CDONT.Newmail") 등을 하려할때
- 서버컴포넌트를 서버에 등록하지 않고서 해당 서버개체를 생성하려할때

---------------------------------------------------------------------------------

Microsoft VBScript 런타임 오류 error '800a000b' 

0으로 나누기 

/파일명.asp, line 에러라인번호 


- 어떤값을 0으로  나누려 할때(0을 다른값으로 나누기는 가능)

---------------------------------------------------------------------------------

ADODB.Connection error '800a0e7a' 

공급자를 찾을 수 없습니다. 올바르게 설치되지 않았을 수 있습니다. 

/파일명.asp, line 에러라인번호


- DB연결문자열에서 지정한 공급자(provider)가 없는 경우 or 오타 (--;)
Ex)  sConnectionString  = "provider=SQLOELDB;Data Source=localhost;Initial Catalog=Northwind;User ID=sa;Password=12345;"

---------------------------------------------------------------------------------

Microsoft OLE DB Provider for SQL Server error '80004005' 

[DBNETLIB][ConnectionOpen (Connect()).]SQL Server가 없거나 액세스할 수 없습니다. 

/파일명.asp, line 에러라인번호


- 지정한 DB서버 주소가 잘못되었거나 DB가 중지상태인 경우

---------------------------------------------------------------------------------

Microsoft OLE DB Provider for SQL Server error '80004005' 

'DB명' 로그인에서 요청한 데이터베이스를 열 수 없습니다. 로그인이 실패했습니다. 

/파일명.asp, line 에러라인번호


- DB연결문자열에서 지정한 Initial Catalog (시작DB)의 DB명이 잘못되거나 없는 경우.

---------------------------------------------------------------------------------

Microsoft OLE DB Provider for SQL Server error '80040e4d' 

'DB계정명' 사용자가 로그인하지 못했습니다. 

/파일명.asp, line 에러라인번호


- 해당 DB계정이 없는 경우
- 해당 계정의 패스워드가 잘못된 경우

---------------------------------------------------------------------------------

Microsoft OLE DB Provider for SQL Server error '80040e2f' 

'테이블명' 테이블, '컬럼명' 열에 NULL 값을 삽입할 수 없습니다. 열에서 null을 사용할 수 없습니다. INSERT이(가) 실패했습니다. 

/파일명.asp, line 에러라인번호


- NOT NULL 로 설정된 컬럼에 NULL 값을 넣으려고 할 경우( option explicit을 설정하지 않은 상태에서 해당 컬럼에 들어갈 변수명이 오타인 경우)

---------------------------------------------------------------------------------

ADODB.Parameters error '800a0e7c' 

매개 변수 개체를 잘못 정의했습니다. 제공된 정보가 일치하지 않거나 완전하지 않습니다. 

/파일명.asp, line 에러라인번호


- 파라메터 컬렉션의 매개변수의 형식을 잘못설정한 경우 
 (Ex.   Cmd.Parameters.Append = Cmd.CreateParameter("MEM_ID",  adnvarchar, adParamInput, 20, sMemId)

- 타입 라이브러리를 지정하지 않고 타입변수(adChar, adVarchar, adInteger, adParamInput 등등.. )를 사용한 경우
 (페이지 상단에    <!--METADATA type="typelib" file="c:Program FilesCommon FilesSYSTEMADOmsado15.dll"-->  이 지정되어 있어야 타입변수 사용가능)

---------------------------------------------------------------------------------

ADODB.Command error '800a0d5d' 

응용 프로그램이 현재 작업에 대해 잘못된 형식을 가진 값을 사용하고 있습니다. 

/파일명.asp, line 에러라인번호

 

- 입력된 값의 형식과 지정한 형식이 다른 경우

Ex) 

sAge = "23세"
Cmd.Parameters.Append = Cmd.CreateParameter("MEM_AGE",  adInteger, adParamInput, 4, sAge)


- 입력될 값의 길이가 지정한 길이보다 클 경우

Ex)

sMemId = "Administrator"
Cmd.Parameters.Append = Cmd.CreateParameter("MEM_ID",  advarchar, adParamInput, 10, sMemId)

---------------------------------------------------------------------------------

Microsoft OLE DB Provider for SQL Server error '80040e57' 

문자열이나 이진 데이터는 잘립니다. 

/파일명.asp, line 에러라인번호


- 입력될 값의 길이와 지정한 값의 길이가 실제 컬럼의 길이보다 클 경우

Ex) 'MEM_ID    varchar(20)   일 경우

sMemId = "ThisIsSuperAdministrator"
Cmd.Parameters.Append = Cmd.CreateParameter("MEM_ID",  advarchar, adParamInput, 30, sMemId)


---------------------------------------------------------------------------------

Microsoft OLE DB Provider for SQL Server error '80040e0c' 

명령 텍스트가 명령 개체에 대하여 설정되지 않았습니다. 

/파일명.asp, line 에러라인번호


- Command 객체에 대해여  CommandText 속성이 지정되지 않은 경우

Ex)

sSql = ""        ' 쿼리가 비어있다
set Cmd = server.createobject("adodb.command")
Cmd.activeconnection = sConnectionString
Cmd.CommandText = sSql     '변수명이 맞는지 확인 


---------------------------------------------------------------------------------
Microsoft OLE DB Provider for SQL Server 오류 '80004005' 
정밀도가 잘못되었습니다. 

- 파라메터 컬렉션의 매개변수의 형식을 잘못설정한 경우 
 (Ex.   Cmd.Parameters.Append = Cmd.CreateParameter("AGE",  AdNumeric, adParamInput, 10, age)
ADO type의 상수에서 일치를 하지 않을 경우 발생

상기에서는 AdNumeric를 adInteger로 변경하면 해결


2020년 10월 27일 화요일

ASP - 함수


1. 대소문자의 구분

  asp 에서는 다른 언어와는 달리 대소문자의 구분이 없다. 그냥 단지 알아보기 쉽게 하기 위해서 대소문자를 사용하는 것이다.
  예) dim strname 는 Dim strName 과 같은 구문이다. 


2. 변수 선언

- 변수나 배열의 변수 선언에는 dim 을 사용한다.
- Option Explicit 를 asp 맨 앞에 사용하여 변수를 꼭 선언하도록 하였으면 모든 변수는 dim 으로 선언하여 사용하여야한다.

예) 변수 선언 : dim strName, strEmail
     배열 선언 : dim monthArry(11)

- Redim : 배열 크기의 재선언에 사용한다.
           redim 의 사용은 처음 배열 선언시에 배열의 크기를 정해 주지 않았을 때에만 가능하다.

- Preserve : 데이터를 저장한 채로 배열의 크기를 늘려준다. 즉, 기존의 들어가 있는 데이터는 그대로 아직 존재한다. 


3. 구분자

- 구분자로는 :(콜론) 이 쓰인다.
- 구분자는 실행할 문장을 한줄단위로 구분짓는 역할을 한다.
예) dim strName : strName = "mshout77" : response.write "
strName = " & strName


4. 연결연산자

- &
- &가 문자열에 쓰이면 문장과 문장을 연결해서 한 문장으로 만들어준다.
- &가 변수에 쓰이면 변수의 값을 & 다음의 값과 이어준다.
- 예) dim strName, strFName, all

       strName = "77"
       strFName = "mshout"
       all = strName&strFName
       response.write all

       결과값은 77mshout 이라고 출력된다.


5. 주석

- ASP에서 주석처리에는 '(작은 따옴표) 가 쓰인다.
- 행에서 ' 다음의 내용은 주석처리되어 해석이 되지 않는다.


6. 함수

1) cdbl(문자열) - 문자열을 소수점이하까지도 출력(큰 숫자에 사용한다)

2) round(숫자,반올림할 위치) - 지정한 소수점 자리에서 반올림한 값을 리턴

3) asc(문자열) - 문자열에서 첫번째 문자에 대한 ansi 코드 번호를 리턴

4) chr(아스키코드번호) - 지정된 번호와 일치하는 ansi 문자로 구성된 문자열을 리턴

5) hex(숫자) - 숫자의 16진수값을 나탸내는 문자열을 리턴

6) fix(숫자) - 숫자의 정수(전체)부분을 리턴 / 음수일때 숫자보다 크거나 같은 첫번째 음의 정수 리턴

7) int(숫자) - 숫자의 정수(전체)부분을 리턴 / 음수일때 숫자보다 작거나 같은 첫번째 음의 정수 리턴

8) sgn(숫자) - 숫자의 부호를 나타내는 정수를 리턴

9) cdate(숫자) - 날짜 형식의 인자값 리턴( 예:cdate(36890) , cdate("2001년 12월 10일") )

10) Clng(숫자) - Long 형식의 문자열 리턴

11) Cstr(숫자) - String 형식의 문자열 리턴

12) Csng(숫자) - Single 형식의 문자열 리턴

13) formatcurrency(숫자) - 숫자를 화폐형식으로 전환

14) formatdatetime(date,1) - date 함수의 표시형태를 바꿈
     - formatdatetime(date,2)
     - formatdatetime(date,3)


15) formatpercent(숫자) - 숫자를 백분율로 표시


16) strConv - 지정한대로 문자를 변환, strConv(문자열,conversion [,LCID])

    conversion 에 가능한 값
     - vbUpperCase 1 문자열을 대문자로 변환
     - vbLowerCase 2 문자열을 소문자로 변환
     - vbPropercase 3 문자열 단어의 첫글자를 대문자로 변환
     - vbWide 4 1바이트문자를 2바이트 문자로 변환
     - vbNarrow 5 2바이트문자를 1바이트문자로 변환
     - vbUnicode 6 시스템의 기본 코드 페이지를 사용하여 문자열을 unicode 로 변환
     - vbFromUnicode 128 unicode 문자열을 시스템의 기본 코드 페이지로 변환


17) Randomize - 난수 발생기를 초기화
    - 난수값 = Int((상한값 - 하한값) + 1) * Rnd + 하한값
    - 예로 1부터 100사이의 난수를 가져오려면, 난수값 = Int(100 - 1 + 1) * Rnd + 1


18) Atn() - 숫자의 아크 탄젠트 값을 리턴


19) Cos() - 각도의 코사인값을 리턴


20) Exp() - e(자연 로그의 밑)의 인자만큼의 제곱을 리턴


21) Log() - 숫자의 자연로그를 리턴


22) Sin() - 각도의 사인값을 리턴


23) Tan() - 각도의 탄젠트값을 리턴


24) InStr("문자열","찾을 문자") - 문자열의 위치 반환 (대소문자 구분하기 때문에 Lcase 또는 Ucase 로 변환하여 사용 권장)


25) InStrRev("문자열","찾을 문자") - 문자열의 위치를 뒤에서 부터 검색해서 반환


26) Lcase("문자열") - 문자열을 소문자로


27) Ucase("문자열") - 문자열을 대문자로


28) Len("문자열") -문자열의 길이 반환


29) Left("문자열",잘라낼 갯수) - 문자열을 왼쪽에서 지정한 갯수만큼 잘라냄


30) Right("문자열",잘라낼 갯수) - 문자열을 오른쪽에서 지정한 갯수만큼 잘라냄


31) Mid("문자열",시작위치,뽑아낼 갯수) - 문자열의 어느 부위를 뽑아냄


32) Yrim("문자열") - 문자열의 양쪽 공백을 제거


33) Ltrim("문자열") - 문자열의 왼쪽 공백을 제거


34) Rtrim("문자열") - 문자열의 오른쪽 공백을 제거


35) Split("문자열","분리자") - 분리자를 기준으로 문자열을 나눔


36) StrReverse("문자열") - 문자열을 뒤집음


37) IsArray() - 변수가 배열인지의 여부를 나타내는 Boolean 값을 리턴


38) IsDate() - 날짜로 변환될 수 있는지의 여부를 나타내는 Boolean 값을 리턴


39) IsEmpty() - 변수가 초기화 될 수 있는지의 여부를 나타내는 Boolean 값을 리턴


40) IsNull() - 유효한 데이터를 포함하고 있는지의 여부를 리턴


41) IsNumeric() - 숫자로 평가될 수 있는지의 여부를 리턴


42) IsObject() - 유효한 ActiveX혹은 OLE 자동화 개체를 참조하는지의 여부를 리턴


43) Vartype() - 변수의 하위 형식을 나타내는 숫자를 리턴한다.


44) now() - 시스템의 시간과 날짜


45) date() - 시스템의 날짜


46) time() - 시스템의 시간


47) year(now()) - 현재의 년도


48) month(now()) - 현재의 월


49) day(now()) - 현재의 일


50) weekday(now()) - 현재의 요일


51) hour(now()) - 현재의 시


52) minute(now()) - 현재의 분


53) second(now()) - 현재의 초


54) DateAdd - 지정된 날짜에 시간을 추가하거나 뺀 새로운 날짜를 반환

   사용법) DateAdd(interval, number, date) 
           - interval : 필수적인 인수로 interval을 추가한 날짜를 나타내는 문자식
                     yyyy 년, q 분기, m 월, y 일(일년 기준), d 일, w 요일, ww 주(일년 기준), h 시, n 분, s 초

           - number : 필수적인 인수로 추가할 간격 수의 수식
                     수식에서 양수는 미래의 날짜, 음수는 과거의 날짜이다. 

           - date : 필수적인 인수로 interval을 추가한 날짜를 나타내는 Variant 또는 리터럴

   예) DateAdd("m",3,Date)  <-- 현재의 날짜에서 3개월을 더함
       DateAdd("m",-3,Date)  <-- 현재의 날짜에서 3개월을 뺌


55) DateDiff - 주어지는 두 날짜의 간격을 반환

   사용법) DateDiff(interval, date1, date2 [,firstdayofweek[, firstweekofyear]]) 
           - interval : 필수적인 인수로 날짜1과 날짜2 사이의 차이를 계산하는 데 사용할 interval의 문자식
                     yyyy 년, q 분기, m 월, y 일(일년 기준), d 일, w 요일, ww 주(일년 기준), h 시, n 분, s 초                 

           - date1, date2 : 필수적인 인수로 날짜식에서 계산에 사용할 두 날짜

           - firstdayofweek : 선택적인 인수로 요일을 지정하는 상수로 지정하지 않으면 일요일로 간주

                            vbUseSystem 0 NLS(National Language Support) API 설정 사용 
                            vbSunday 1 일요일(기본값) 
                            vbMonday 2 월요일 
                            vbTuesday 3 화요일 
                            vbWednesday 4 수요일 
                            vbThursday 5 목요일 
                            vbFriday 6 금요일 
                            vbSaturday 7 토요일 

           - firstweekofyear : 선택적인 인수로 연도를 기준으로 한 첫째 주를 지정하는 상수
                            지정하지 않으면 1월 1일을 포함하는 주를 첫째 주로 간주한다. 
                            vbUseSystem 0 NLS(National Language Support) API 설정 사용 
                            vbFirstJan1 1 1월 1일을 포함하는 주에서 시작(기본값) 
                            vbFirstFourDays 2 새해의 처음 4일을 포함하는 주에서 시작 
                            vbFirstFullWeek 3 새해의 처음 한 주일(7일)을 포함하는 주에서 시작

   예) DateDiff("h", "2001년 12월 30일", Date) 
       DateDiff("n", "2001년 12월 30일 09:30:00", now) 
       DateDiff("s", "2001년 12월 30일 09:30:00", now) 


56) DatePart - 주어진 날짜의 지정된 부분을 반환한다. 

   사용법) DatePart(interval, date[, firstdayofweek[, firstweekofyear]]) 
           - interval : 필수적인 인수로 반환할 시간 간격의 문자식이다.
                     yyyy 년, q 분기, m 월, y 일(일년 기준), d 일, w 요일, ww 주(일년 기준), h 시, n 분, s 초

           - date : 필수적인 인수로 계산할 날짜식

           - firstdayof week : 선택적인 인수로 요일을 지정하는 상수로서 지정하지 않으면 일요일로 간주

                            vbUseSystem 0 NLS(National Language Support) API 설정 사용 
                            vbSunday 1 일요일(기본값) 
                            vbMonday 2 월요일 
                            vbTuesday 3 화요일 
                            vbWednesday 4 수요일 
                            vbThursday 5 목요일 
                            vbFriday 6 금요일 
                            vbSaturday 7 토요일

           - firstweekofyear : 선택적인 인수로 연도를 기준으로 한 첫째 주를 지정하는 상수
                            지정하지 않으면 1월 1일을 포함하는 주를 첫째 주로 간주한다. 
                            vbUseSystem 0 NLS(National Language Support) API 설정 사용 
                            vbFirstJan1 1 1월 1일을 포함하는 주에서 시작(기본값) 
                            vbFirstFourDays 2 새해의 처음 4일을 포함하는 주에서 시작 
                            vbFirstFullWeek 3 새해의 처음 한 주일(7일)을 포함하는 주에서 시작

   예) DatePart("q", now)


57) DateSerial - 지정된 년, 월, 일의 Date 하위 형식인 Variant를 반환한다. 
               즉, 임의의 숫자를 입력받아 날짜 형식으로 반환하는 함수이다. 

   사용법) DateSerial(year, month, day) 
           year : 100에서 9999까지의 수 또는 수식 
           month : 모든 수식 
           day : 모든 수식 
   예) DateSerial(2001, 12, 25) 


58) DateValue - Date 하위 형식의 Variant를 반환한다. 

   사용법) DateValue(date)
   예) DateValue("2000년 12월 25일") 


59) Replace - 문자열 변경

Replace("[문자열]", "[변경할 문자열 패턴]", "[새로운 문자열]")
(예) Response.Write Replace(str, "문자열", "String") & Replace(str, "문자열", "String")

Str = "오늘은 12월 24일 크리스마스 이브입니다"
replace_Str = replace(Str, "이브", "오브")

MSSQL - Cursor vs Temp Table

#테이블 변수사용의 예 use pubs go declare @tmptable table (     nid int identity(1,1) not null,     title varchar (80) not null ) -- 테이블 변수 선언 inse...