locked
Setting Class Value Equal to List RRS feed

  • Question

  • User1122355199 posted

    Hello everyone and thanks for your help in advance. I am a C# newbie having worked with Vb.Net previously.  I have a data access function that looks like:

                myDBAccess.tblPtmstr1 ptMstr1 = new myDBAccess.tblPtmstr1();
                List<myDBAccess.tblPtmstr1> PatientDetails = new List<myDBAccess.tblPtmstr1>();
                Models.Patient pd = new Models.Patient();
                PatientDetails = ptMstr1.GetPatientDetails("5732");
                pd.PatientDetails = PatientDetails;

    The class I am trying to populate looks like:

        public class Patient
        {
            public List<myDBAccess.tblPtmstr1> PatientDetails { get; set; }
        }

    But this seems to not populate the class.  I'm assuming this can be done, but I am at a loss as to how to do this.  Any help would be appreciated.

    Thursday, January 25, 2018 12:31 AM

All replies

  • User2103319870 posted

     PatientDetails = ptMstr1.GetPatientDetails("5732");

    I guess the return type of GetPatientDetails method is of "myDBAccess.tblPtmstr1" type. You need to get the value first to object of "myDBAccess.tblPtmstr1" and then add the value to list like below

    myDBAccess.tblPtmstr1 ptMstr1 = new myDBAccess.tblPtmstr1();
                List<myDBAccess.tblPtmstr1> PatientDetails = new List<myDBAccess.tblPtmstr1>();
    
                myDBAccess.tblPtmstr1 tbl = new myDBAccess.tblPtmstr1();
                tbl = ptMstr1.GetPatientDetails("5732");
                //Add patient details to list
                PatientDetails.Add(tbl);
    
                Models.Patient pd = new Models.Patient();
                pd.PatientDetails = PatientDetails;

    Thursday, January 25, 2018 12:42 AM
  • User1122355199 posted

    Thanks for the response.  I'm not making things very clear because of my sloppy code.  The return type of GetPatientDetails is List<myDBAccess.tblPtmstr1>().  I've been all over the place with this, but can't get it right.

    Thursday, January 25, 2018 12:59 AM
  • User303363814 posted

    Does GetPatientDetails("5732") actually return anything?  Have you checked with the debugger?

    Thursday, January 25, 2018 6:37 AM
  • User1122355199 posted

    Thanks for the response.  For some reason, my locals window on the debugger appears blank.  But I was able to place some console writing and it does appear that the expected one row of data is returned.

    Thursday, January 25, 2018 12:07 PM
  • User1122355199 posted

    I have definitely verified the list of 1 record is created and returned.  The code is failing at:

    Models.Patient pd = new Models.Patient();
    pd.PatientDetails = PatientDetails;  // Code fails here

    Oddly, I have tried placing this in a 

                try
                {
    }
                catch (System.Exception ex)
                {

    but it seems to fall right through block without throwing any exceptions.

    Thursday, January 25, 2018 8:01 PM
  • User475983607 posted

    A console example that hopefully explains how to structure the code.

    Shared Model Layer

    //Shared model library
    namespace ConsoleDemo.SharedModelLayer
    {
        public class Patient
        {
            public int PatientId { get; set; }
            public string Name { get; set; }
        }
    
        public class PatientDetial
        {
            public int PatientDetialId { get; set; }
            public int PatientId { get; set; }
            public string DetailText { get; set; }
        }
    }
    

    Data Access Layer

    namespace ConsoleDemo.DataAccessLayer
    {
        //Data access layer
        public class PatientDb
        {
            public PatientDb()
            {
                //This builds a fake DB so the queries work.
                PopulateFakePatientDb();
            }
    
            /*
             * This is not used in the demo but it shows an example 
             * of what kind of stuff that belongs in a data access layer.
            */
            public string connectionStringNode;
            public PatientDb(string ConnectionStringNode)
            {
                connectionStringNode = ConnectionStringNode;
            }
    
            //Get a patient
            public SharedModelLayer.Patient GetPatientById(int PatientId)
            {
                return Patients.Where(m => m.PatientId == PatientId).FirstOrDefault();
            }
    
            //Get patient details by Id
            public List<SharedModelLayer.PatientDetial> GetPatientDetailsByPatientId(int PatientId)
            {
                return PatientDetials.Where(m => m.PatientId == PatientId).ToList();
            }
    
            //Overload: Get patient details by Patient
            public List<SharedModelLayer.PatientDetial> GetPatientDetailsByPatient(SharedModelLayer.Patient Patient)
            {
                return PatientDetials.Where(m => m.PatientId == Patient.PatientId).ToList();
            }
    
            //
            //Fake DB Stuff
            //
            private List<SharedModelLayer.Patient> Patients;
            private List<SharedModelLayer.PatientDetial> PatientDetials;
            private void PopulateFakePatientDb()
            {
                //In-memory patinets
                Patients = new List<SharedModelLayer.Patient>() {
                    new SharedModelLayer.Patient()
                    {
                        PatientId = 1,
                        Name = "Foo"
                    },
                     new SharedModelLayer.Patient()
                    {
                        PatientId = 2,
                        Name = "Bar"
                    }
                };
    
                //In-memory Patient Details
                PatientDetials = new List<SharedModelLayer.PatientDetial>()
                {
                    new SharedModelLayer.PatientDetial()
                    {
                        PatientId = 1,
                        PatientDetialId = 1,
                        DetailText = "Foo is sick of bar."
                    },
                    new SharedModelLayer.PatientDetial()
                    {
                        PatientId = 1,
                        PatientDetialId = 2,
                        DetailText = "Foo's other detail record."
                    },
                    new SharedModelLayer.PatientDetial()
                    {
                        PatientId = 2,
                        PatientDetialId = 3,
                        DetailText = "Bar said Hello World!"
                    }
                };
    
            }
        }
    }

    Console app

            static void Main(string[] args)
            {
    
                //Data Access layer
                DataAccessLayer.PatientDb Db = new DataAccessLayer.PatientDb();
    
                //Local View Model that is only used in the console but could be shared if we wanted
                ConsolePatientViewModel PatientVm = new ConsolePatientViewModel();
    
                int PatientId = 1;
    
                //Fill the Patient
                PatientVm.Patient = Db.GetPatientById(PatientId);
                if(PatientVm.Patient == null)
                {
                    Console.WriteLine("Patient Not Found!");
                    Console.ReadLine();
                    return;
                }
    
                //Fill the Patient Detials
                PatientVm.PatientDetails = Db.GetPatientDetailsByPatientId(PatientId);
    
                //Patient Report
                Console.WriteLine("Id\tName");
                Console.WriteLine("--\t----");
                Console.WriteLine("{0}\t{1}", PatientVm.Patient.PatientId, PatientVm.Patient.Name);
                Console.WriteLine();
                foreach (SharedModelLayer.PatientDetial detail in PatientVm.PatientDetails)
                {
                    Console.WriteLine("Detail: {0}", detail.DetailText);
                }
                Console.ReadLine();
                
            }
    
            //This view model is only used in the console to render a report
            public class ConsolePatientViewModel
            {
                public SharedModelLayer.Patient Patient { get; set; }
                public List<SharedModelLayer.PatientDetial> PatientDetails { get; set; }
            }

    Edit: Copy error, missed the data access namespace.

    Thursday, January 25, 2018 9:52 PM
  • User1122355199 posted

    Thanks for the response and it is excellent code, but not completely on-point to the question asked.  In your example, the lists that are created are based on a method that loops through a dataset of some type and sets the value of each field, row by row.  The question I am asking is, can a model be set up like:

            public class PatientDetailDB
            {
                public List<myNodel.tblPtmstr1> PatientDetailsList { get; set; }
            }

    Then populated by a method that returns a List<myNodel.tblPtmstr1>.  Obviously, I could loop through the returned list to populate the new class, but I would think (perhaps incorrectly) there is a way to set the class directly.  I know two lists can be set equal to each other, but perhaps not in a class.

    Saturday, January 27, 2018 2:48 AM
  • User475983607 posted

    The problem you are trying to solve is not clear.

    Thanks for the response and it is excellent code, but not completely on-point to the question asked.  In your example, the lists that are created are based on a method that loops through a dataset of some type and sets the value of each field, row by row.

    Maybe you are referring to the in-memory DB?  If so, that is just a database mock.  Would it help if I created an actual ADO.NET connection to DB tables and returned record sets?  Otherwise can you post the loop that you're referring to?

    Then populated by a method that returns a List<myNodel.tblPtmstr1>. 

    The example code has a method that returns a List<T> which is used to populate a class property of the same type; List<t>.

    Obviously, I could loop through the returned list to populate the new class, but I would think (perhaps incorrectly) there is a way to set the class directly.  I know two lists can be set equal to each other, but perhaps not in a class.

    I think this last statement is where the confusion is.   Can you show us the source code for myNodel.tblPtmstr1?

    Saturday, January 27, 2018 2:00 PM
  • User1122355199 posted

    Thanks for the response.  Code for myModel.tblPtmstr1:

            public class PatientDetailDB
            {
                public List<myExternalClass.tblPtmstr1> PatientDetailsList { get; set; }
            }

    The code for the model in the external class:

    namespace myExternalClass
    {
        public class tblPtmstr1
        {
            public int PatientID { get; set; }
    
            public string PatientLastName { get; set; }
    
            public string PatientFirstName_Old { get; set; }
    
            public string PatientFirstName { get; set; }
    
            public string PatientMiddleName { get; set; }
    
            public string PatientAddress { get; set; }
    
            public string PatientAddress2 { get; set; }
    
            public string PatientCity { get; set; }
    
            public string PatientState { get; set; }
    
            public string PatientZip { get; set; }
    
            public string PatientPhone { get; set; }
        }
    }

    The external class also has a method GetPatientDetails(MRNumber) that returns a List<Of tblPtmstr1> (Yes, I know this isn't the optimal way to handle things).  So I modified your example to:

        class SharedModelLayer
        {
    
            public class Patient
            {
                public int PatientId { get; set; }
                public string Name { get; set; }
            }
    
            public class PatientDetail
            {
    
                public int PatientDetailId { get; set; }
                public int PatientId { get; set; }
                public string DetailText { get; set; }
            }
    
            public class PatientDetailDB
            {
                public List<myExternalClass.tblPtmstr1> PatientDetailsList { get; set; }
            }
        }

    Then I tried modifying PatientDb, adding:

            public List<SharedModelLayer.PatientDetailDB> GetPatientDetailsByMRNumber()
            {
                KidsMedicalDB_MVC.tblPtmstr1 patdetails = new KidsMedicalDB_MVC.tblPtmstr1();
                List<KidsMedicalDB_MVC.tblPtmstr1> PatientDetailsList = new List<KidsMedicalDB_MVC.tblPtmstr1>();
                PatientDetailsList = patdetails.GetPatientDetails("12345");
                return PatientDetailsList; //causes a cannot convert error
            }

    At the core is my need to make the tblPtmstr1 model as accessible as possible throughout this application as well as other applications.  Maybe I am attacking the problem all wrong.

    Saturday, January 27, 2018 5:34 PM
  • User475983607 posted

    kmcnet

    At the core is my need to make the tblPtmstr1 model as accessible as possible throughout this application as well as other applications.  Maybe I am attacking the problem all wrong.

    List<SharedModelLayer.PatientDetailDB> and List<KidsMedicalDB_MVC.tblPtmstr1> are two different types. They might have identical property names but the classes are in different namespaces.

            public List<SharedModelLayer.PatientDetailDB> GetPatientDetailsByMRNumber()
            {
                KidsMedicalDB_MVC.tblPtmstr1 patdetails = new KidsMedicalDB_MVC.tblPtmstr1();
                List<KidsMedicalDB_MVC.tblPtmstr1> PatientDetailsList = new List<KidsMedicalDB_MVC.tblPtmstr1>();
                PatientDetailsList = patdetails.GetPatientDetails("12345");
                return PatientDetailsList; //causes a cannot convert error
            }

    Let's say we want to create a class named Table.  It might look like this.

    public class Table 
    {
    	public int Columns {get; set;}
    	public int  Rows {get; set;} 
    }

    Or like this depending on what kind of table we're talking about.

    public class Table 
    {
    	public string Material {get; set;}
    	public string Type [get; set;} 
    	public bool ChairsIncluded {get; set;}
    }
    

    This is where a namespace comes in.

    namespace Furniture
    {
    	public class Table 
    	{
    		public string Material {get; set;}
    		public string Type [get; set;} 
    		public bool ChairsIncluded {get; set;}
    	}
    }
    
    namespace Html
    {
    	public class Table 
    	{
    		public int Columns {get; set;}
    		public int  Rows [get; set;} 
    	}
    }

    Now it is easy to distinguish between each type of Table object.  .NET considers classes in differnet namespaces as differnet types.  

    https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/namespaces/

    Yours is a very simple problem to solve though.  Create a class library project, add the tblPtmstr1 class file to the project, and reference the class library in whatever project or applications you like.  Which, by the way, is exactly how the sample code above works.

    Saturday, January 27, 2018 10:12 PM
  • User303363814 posted

    it does appear that the expected one row of data is returned.
    You need to be 100% triple positively sure.

    Do you know how to use the debugger? (When I say 'will' in the next few paragraphs that is exactly what will happen.  If it does not then you have much bigger problems).

    Set the cursor somewhere in the line

    PatientDetails = ptMstr1.GetPatientDetails("5732");

    Go up to the Debug menu and choose 'Toggle Breakpoint'. The text will get a brown background and a nice red dot will appear in the left margin.

    Run your code (press F5). Execution will stop on the breakpoint line. You will see a yellow arrow over the top of the red dot. The 'Locals' window WILL have all the local variables visible at this point in the code.  Check them.  Are they all correct?

    Press F11 to step into the GetPatientDetails method.  The 'Locals' window WILL now show the locals variables visible in this method.  Use F10 to step, one line at a time, through the method.  At each and every step check that all the locals are exactly what you expect them to be.  If the GetPatientDetails method calls other code then use F11 to step into that code and repeat the process (don't step into the .Net code, just your code)

    Eventually, you will get to the end of GetPatientDetails and return to the calling code that you have shown us.  The PatientDetails variable will be set.  Is it 100% correct.  Double check (don't write console variables or guess, use the debugger - check, check, check.  The easiest person in the world to fool is yourself).

    Now use F10 to step over the next line (pd.PatientDetails = PatientDetails).  The value of pd.PatientDetails will now be equal to the value of Patient Details (assignment of variables does work!)

    What do you learn?

    (The debugger is your friend.  Learn how to use it and your programming experience will be a LOT less frustrating)

    Saturday, January 27, 2018 10:50 PM
  • User303363814 posted

    Some general C# comments, if I may.

    Don't use Hungarian notation.  tblPtmstr1 should be PatientMaster (or whatever it is - I can't tell from the Hungarian notation).  All the Hungarian notation tells me is that it is a Table - but it isn't! It is a class.  Name things after what they are.

    Don't prefix things with 'my'.  It's just noise.

    Make use of the 'using' directive.  At the top of the first little piece of code you showed you need to have

    using DBAccess;
    using Models;

    Don't repeat yourself.  The first piece of code should be

    var patientMaster = new PatientMaster();
    var patient = new Patient();
    patient.PatientDetails = patientMaster.GetPatientDetails("5732");

    (Why, oh why, do you pass a number as a string?  C# is a strongly typed language.  Use it's strengths for maximum benefit.  Don't work against.)

    Think carefully about names.  Names matter.  A property of the Patient class should not be called PatientDetails.  Just call it Details, we already know it is a Patient - don't clutter the code by saying the same thing over and over again.  But ... are you sure 'Details' is the best name?  Just as we would never call something 'Thing' or 'Object' because they are too broad and convey no information, is 'Details' the best name you can come up with?  (It might be - only you know the answer).

    Don't nest classes.

    Yes, I know C# supports it.  But nested classes are a more advanced feature with specific uses.  Unless it is essential to use a nested class (or you have a couple of years under your belt) then don't do it.  It just makes life more complicated for no gain.  (Or is SharedModelLayer supposed to be a namespace?)

    Namespaces

    Namespaces are good.  They let you group things together.  That is the key, grouping.  Don't just have another namespace because you can.  Keep things in the one space, it make reading code easier, writing code easier and maintenance easier.

    Saturday, January 27, 2018 11:14 PM
  • User1122355199 posted

    Thanks for the response.

    PatientDetails = ptMstr1.GetPatientDetails("5732");

    Done.

    Go up to the Debug menu and choose 'Toggle Breakpoint'. The text will get a brown background and a nice red dot will appear in the left margin.

    Done.

    Run your code (press F5). Execution will stop on the breakpoint line. You will see a yellow arrow over the top of the red dot. The 'Locals' window WILL have all the local variables visible at this point in the code.  Check them.  Are they all correct?

    As I said before, the Locals window is blank and there is no yellow arrow.  For the record, I restarted VS 2015 and also restarted my computer, but had the same result.  

    Sunday, January 28, 2018 12:41 AM
  • User303363814 posted

    This means that the code have shown is not even running - no wonder the property is not being set!

    The code you have shown is being called from somewhere else.  Put a breakpoint in that code.

       - If it is hit then single step to find out why the code you have shown is not being called.

       - If it is not hit then put the breakpoint in a caller of that code.  Repeat until you discover why the code is not being called.

    Sunday, January 28, 2018 12:54 AM
  • User1122355199 posted

    Thanks for the response.  I appreciate the help and I think you are flushing out the issues I am having.  I'm understanding what you are saying, but having problems reaching my solution.

    List<SharedModelLayer.PatientDetailDB> and List<KidsMedicalDB_MVC.tblPtmstr1> are two different types. They might have identical property names but the classes are in different namespaces.

    You are partially correct in that they are in different namespaces, but they are identical in structure, both deriving from the ExternalClass.tblPtmstr1 class that is referenced in the current MVC project.  So it is not entirely analogous to the tables example you demonstrated since they are identical in structure.

    Yours is a very simple problem to solve though.  Create a class library project,

    Which I have done:

    add the tblPtmstr1 class file to the project

    Using your example, I made these modifications:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace DataAccessLayerExample
    {
        class SharedModelLayer
        {
    
            public class Patient
            {
                public int PatientId { get; set; }
                public string Name { get; set; }
            }
    
            public class PatientDetail
            {
    
                public int PatientDetailId { get; set; }
                public int PatientId { get; set; }
                public string DetailText { get; set; }
            }
    
            public class PatientDetailDB
            {
                public List<ExternalClass.tblPtmstr1> PatientDetailsList { get; set; }
            }
        }
    }

    reference the class library in whatever project or applications you like.  Which, by the way, is exactly how the sample code above works.

    And this is where I fall apart:

            public List<SharedModelLayer.PatientDetailDB> GetPatientDetailsByMRNumber()
            {
                KidsMedicalDB_MVC.tblPtmstr1 patdetails = new KidsMedicalDB_MVC.tblPtmstr1();
                List<KidsMedicalDB_MVC.tblPtmstr1> patdetailslist = new List<KidsMedicalDB_MVC.tblPtmstr1>();
                patdetailslist = patdetails.GetPatientDetails("12345");  // method to return populated List<Of tblPtmstr1
                return  patdetailslist;  // mismatch error
            }

    So working with your previous posts, I could abandon using the method that returns the list and make the ADO call within the project, or I could loop through the returned List<Of tblPtmstr1 to populate the model ExternalClass.tblPtmstr1.  But since I have a method that returns the list, I would think that could be passed to the class:

            public class PatientDetailDB
            {
                public List<ExternalClass.tblPtmstr1> PatientDetailsList { get; set; }
            }

    within the SharedModelLayer.  

    Sunday, January 28, 2018 5:56 PM
  • User475983607 posted

    kmcnet

    You are partially correct in that they are in different namespaces, but they are identical in structure, both deriving from the ExternalClass.tblPtmstr1 class that is referenced in the current MVC project.  So it is not entirely analogous to the tables example you demonstrated since they are identical in structure.

    Different namespaces are different types regardless of inheritance or class structure.  Your current design confirms this as well.  You could pull this off with an Interface but I don't recommend doing that as a single class in a shared library will work fine.  

    kmcnet

    Using your example, I made these modifications:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace DataAccessLayerExample
    {
        class SharedModelLayer
        {
    
            public class Patient
            {
                public int PatientId { get; set; }
                public string Name { get; set; }
            }
    
            public class PatientDetail
            {
    
                public int PatientDetailId { get; set; }
                public int PatientId { get; set; }
                public string DetailText { get; set; }
            }
    
            public class PatientDetailDB
            {
                public List<ExternalClass.tblPtmstr1> PatientDetailsList { get; set; }
            }
        }
    }

    Can you explain the thought process behind the nexted types?  Are you trying to create a closure?  Be aware that a class without an access modifier defaults to internal and is only accessable to code within the same assembly. 

    Sunday, January 28, 2018 6:48 PM
  • User1122355199 posted

    Perhaps you have hit the nail on the head with my lack of understanding.

    Can you explain the thought process behind the nexted types?  Are you trying to create a closure?  Be aware that a class without an access modifier defaults to internal and is only accessable to code within the same assembly. 

    I assume by nested types, you are referring to 

            public class PatientDetailDB
            {
                public List<ExternalClass.tblPtmstr1> PatientDetailsList { get; set; }
            }

    Perhaps, I only need to add:

    public List<ExternalClass.tblPtmstr1> PatientDetailsList { get; set; }

    within each viewmodel that requires it, then populate it within the controller through some type method (either ADO or returning a List<Of.  

    Sunday, January 28, 2018 7:45 PM
  • User475983607 posted

    I assume by nested types, you are referring to 

            public class PatientDetailDB
            {
                public List<ExternalClass.tblPtmstr1> PatientDetailsList { get; set; }
            }

    No, this is were you are using nested types.

    namespace DataAccessLayerExample
    {
        class SharedModelLayer
        {
    
            public class Patient
            {
                public int PatientId { get; set; }
                public string Name { get; set; }
            }

    C# programming guide that explains nested types.  

    Perhaps, I only need to add:

    public List<ExternalClass.tblPtmstr1> PatientDetailsList { get; set; }

    I don't see any reason to encapsulate a single List<T> within a class.

    within each viewmodel that requires it, then populate it within the controller through some type method (either ADO or returning a List<Of.  

    I agree and that's how the demo code works.

    https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/nested-types

    Sunday, January 28, 2018 8:02 PM
  • User1122355199 posted

    Thanks for the response.

    No, this is were you are using nested types.

    namespace DataAccessLayerExample
    {
        class SharedModelLayer
        {
    
            public class Patient
            {
                public int PatientId { get; set; }
                public string Name { get; set; }
            }

    But this is the code you supplied in your example.  See above.  Why since you're implying it's not necessary?

    I agree and that's how the demo code works.

    Where?

    Sunday, January 28, 2018 8:35 PM
  • User475983607 posted

    kmcnet

    But this is the code you supplied in your example.  See above.  Why since you're implying it's not necessary?

    The demo code does NOT have nested typed.  You added that bit and that's why I asked.

    Demo Code

    //Shared model library
    namespace ConsoleDemo.SharedModelLayer
    {
        public class Patient
        {
            public int PatientId { get; set; }
            public string Name { get; set; }
        }
    
        public class PatientDetial
        {
            public int PatientDetialId { get; set; }
            public int PatientId { get; set; }
            public string DetailText { get; set; }
        }
    }

    Where?

    The whole thing. 

    Sunday, January 28, 2018 8:52 PM
  • User1122355199 posted

    Thanks again for the response.  Your first reply to this post:

    A console example that hopefully explains how to structure the code.
    Shared Model Layer
    //Shared model library
    namespace ConsoleDemo.SharedModelLayer
    {
        public class Patient
        {
            public int PatientId { get; set; }
            public string Name { get; set; }
        }
    
        public class PatientDetial
        {
            public int PatientDetialId { get; set; }
            public int PatientId { get; set; }
            public string DetailText { get; set; }
        }
    }

    Perhaps I misunderstand, but the only code I added to the SharedModelLayer was:

            public class PatientDetailDB
            {
                public List<KidsMedicalDB_MVC.tblPtmstr1> PatientDetailsList { get; set; }
            }

    which I thought you told me was not nested.  In any event, the problem I am trying to solve is:

    1.  Create a reusable partial view as a header that can be utilized on multiple pages

    2.  That uses an external class library for the model, ExternalClass.tblPtmstr1

    3. That is populated by some type of reusable method that can accept a PatientID parameter and return a populated ExternalModel.tblPtmstr1 or a populated List<Of ExternalModel.tblPtmstr1

    So my thinking of using the code:

            public class PatientDetailDB
            {
                public List<ExternalClass.tblPtmstr1> PatientDetailsList { get; set; }
            }

    At the hear of my conundrum is my understanding the partial view will require something like:

    @model Namespace.Models.ViewModelIAmUsing

    to populate this partial view.  Obviously, if the viewmodel changed, the partiel view won't render.

    Sunday, January 28, 2018 11:44 PM
  • User475983607 posted

    kmcnet

    1.  Create a reusable partial view as a header that can be utilized on multiple pages

    2.  That uses an external class library for the model, ExternalClass.tblPtmstr1

    3. That is populated by some type of reusable method that can accept a PatientID parameter and return a populated ExternalModel.tblPtmstr1 or a populated List<Of ExternalModel.tblPtmstr1

    I provided two working examples that handle steps 1-3.  I'm not sure what else I can do for you.

    Monday, January 29, 2018 12:58 AM
  • User1122355199 posted

    If I am not mistaken, your example built the lists by looping through a mock list setting the value through each iteration rather than having the list already pre-built from a method and then setting the model to that list.  As you can see, the model I created is already a list:

            public class PatientDetailDB
            {
                public List<KidsMedicalDB_MVC.tblPtmstr1> PatientDetailsList { get; set; }
            }

    So, since I am using an external class model, trying to set the lists equal cannot be done, therefore, I need to loop though the list returned by the method and create a new list.

    Monday, January 29, 2018 1:23 AM
  • User303363814 posted

    But your code is not even being executed ....  changing code that does not run will not alter anything.

    Monday, January 29, 2018 5:53 AM
  • User475983607 posted

    If I am not mistaken, your example built the lists by looping through a mock list setting the value through each iteration rather than having the list already pre-built from a method and then setting the model to that list.  As you can see, the model I created is already a list:

    Something is not right with your understanding of the demo code.

    kmcnet

    So, since I am using an external class model, trying to set the lists equal cannot be done, therefore, I need to loop though the list returned by the method and create a new list.

    What is an "external class model" and why is an "external class model" needed in your design?  

    Monday, January 29, 2018 11:58 AM
  • User1122355199 posted

    Lets' move past the notion of code not being executed as I have verified data is being returned.  There are many iterations of code being tried.  Here is the point that is not exactly being addressed.  Let me go through this again.  I have an external class that looks like this:

    namespace ExternalClass
    {
        public class tblPtmstr1
        {
            public int PatientID { get; set; }
    
            public string PatientLastName { get; set; }
    
            public string PatientFirstName_Old { get; set; }
    
            public string PatientFirstName { get; set; }
    
            public string PatientMiddleName { get; set; }
    
            public string PatientAddress { get; set; }
    
            public string PatientAddress2 { get; set; }
    
            public string PatientCity { get; set; }
    
            public string PatientState { get; set; }
    
            public string PatientZip { get; set; }
    
            public string PatientPhone { get; set; }
        }
    }

    I want to use this as a model inside of my MVC project.  I have added a reference to the external project and can successfully access this class.  

    Question 1:  How do I set up my model?  

    Part 2.  I have a method that receives a PatientID and returns a List<ExternalClass.tblPtmstr1>.  

    Question 2:  How do I use this list to populate the model?

    I have tried augmenting the examples provided, but there seems to be differences working with external class libraries, which is starting to look like a really bad idea.

    Monday, January 29, 2018 12:29 PM
  • User475983607 posted

    Question 1:  How do I set up my model?  

    Part 2.  I have a method that receives a PatientID and returns a List<ExternalClass.tblPtmstr1>.  

    Can you explain what you mean by "setup"?  

    Question 2:  How do I use this list to populate the model?

    I have tried augmenting the examples provided, but there seems to be differences working with external class libraries, which is starting to look like a really bad idea.

    You using the term "external class" as if it is common knowledge.  Can you explain what an "external class" class means in your design?

    The following is what I think of when I hear the term external class.

    https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern

    Monday, January 29, 2018 12:46 PM
  • User1122355199 posted

    I think I've been pretty clear that this is an external class library.

    Monday, January 29, 2018 1:56 PM
  • User1122355199 posted

    Let me rephrase for clarity, that this is a class library outside of the MVC project that will be referenced by the project.

    Monday, January 29, 2018 2:05 PM
  • User475983607 posted

    kmcnet

    I think I've been pretty clear that this is an external class library.

    I have to ask because you are making incorrect assumption about language constructs and I want to make sure we are on the same page when it comes to intent.  I'm having a hard time gleaming intent for the code as the code is very confusing.

    kmcnet

    Let me rephrase for clarity, that this is a class library outside of the MVC project that will be referenced by the project.

    That should not be a problem.  Next, we need to figure out if this is a bug or a learning opportunity.

    I assume the following code has been changed as the defined return type (List<SharedModelLayer.PatientDetailDB>) is not the same as the actual return type; List<KidsMedicalDB_MVC.tblPtmstr1>.

            public List<SharedModelLayer.PatientDetailDB> GetPatientDetailsByMRNumber()
            {
                KidsMedicalDB_MVC.tblPtmstr1 patdetails = new KidsMedicalDB_MVC.tblPtmstr1();
                List<KidsMedicalDB_MVC.tblPtmstr1> patdetailslist = new List<KidsMedicalDB_MVC.tblPtmstr1>();
                patdetailslist = patdetails.GetPatientDetails("12345");  // method to return populated List<Of tblPtmstr1
                return  patdetailslist;  // mismatch error
            }

    I'm guessing that you've changed the code to convert a List<KidsMedicalDB_MVC.tblPtmstr1> to a List<SharedModelLayer.PatientDetailDB>?  Can you explain why the conversion is necessary?  Is Visual Studio reporting a circular reference error or maybe some other kind of error?

    I would refactor the method above to this.

    public List<KidsMedicalDB_MVC.tblPtmstr1> GetPatientDetailsByMRNumber()
    {
    	KidsMedicalDB_MVC.tblPtmstr1 patdetails = new KidsMedicalDB_MVC.tblPtmstr1();
    	return patdetails.GetPatientDetails("12345");  
    }

    And the ViewModel to this.  Where the return types equals the property type similar to the demo code.

    public class PatientDetailDB
    {
    	public List<KidsMedicalDB_MVC.tblPtmstr1> PatientDetailsList { get; set; }
    }

    I'm guessing that you really want this though.

    public List<ExternalClass.tblPtmstr1> GetPatientDetailsByMRNumber()
    {
    	KidsMedicalDB_MVC.tblPtmstr1 patdetails = new KidsMedicalDB_MVC.tblPtmstr1();
    	return patdetails.GetPatientDetails("12345");  
    }
    
    public class PatientDetailDB
    {
    	public List<ExternalClass.tblPtmstr1> PatientDetailsList { get; set; }
    }

    Wich means you need to refactor the data access layer and the GetPatientDetails("12345") method.  Or maybe move code around a bit.

    Can you post the data access layer code so we can see what the code is doing?

    Monday, January 29, 2018 2:41 PM
  • User1122355199 posted

    Here is the entire class:

    using KidsMedicalDB_MVC;
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace KidsMedicalDB_MVC
    {
        public class tblPtmstr1
        {
            public int PatientID { get; set; }
    
            public string PatientLastName { get; set; }
    
            public string PatientFirstName_Old { get; set; }
    
            public string PatientFirstName { get; set; }
    
            public string PatientMiddleName { get; set; }
    
            public string PatientAddress { get; set; }
    
            public string PatientAddress2 { get; set; }
    
            public string PatientCity { get; set; }
    
            public string PatientState { get; set; }
    
            public string PatientZip { get; set; }
    
            public string PatientPhone { get; set; }
            public List<tblPtmstr1> PatientDetails = new List<tblPtmstr1>();
    
            public List<tblPtmstr1> GetPatientDetails(string MRNumber)
            {
                //Code to retrieve _Dataview using ADO
    
    
                return GetDetailLines(PatientManager._DataView);
    
    
            }
    
            public List<tblPtmstr1> GetDetailLines(DataView DetailLines)
            {
                foreach (DataRowView DetailLine in DetailLines)
                {
    
    
                    if (DetailLine["PatientLastName"] != DBNull.Value)
                    {
                        PatientLastName = DetailLine["PatientLastName"].ToString();
                    }
                    //
                    if (DetailLine["PatientFirstName"] != DBNull.Value)
                    {
                        PatientFirstName = DetailLine["PatientFirstName"].ToString();
                    }
                    //
                    if (DetailLine["PatientMiddleName"] != DBNull.Value)
                    {
                        PatientMiddleName = DetailLine["PatientMiddleName"].ToString();
                    }
                    //
                    if (DetailLine["PatientDOB"] != DBNull.Value)
                    {
                        PatientDOB = DetailLine["PatientDOB"].ToString();
                    }
                    //
                    if (DetailLine["Gender"] != DBNull.Value)
                    {
                        Gender = DetailLine["Gender"].ToString();
                    }
                    //
                    if (DetailLine["PatientPhone"] != DBNull.Value)
                    {
                        PatientPhone = DetailLine["PatientPhone"].ToString();
                    }
                    
                    //
                    PatientDetails.Add(new tblPtmstr1
                    {                   
                        
                        PatientID = PatientID,
                        PatientFirstName = PatientFirstName,
                        PatientLastName = PatientLastName,
                        PatientMiddleName = PatientMiddleName,
                        PatientDOB = PatientDOB,
                        Gender = Gender,
                        PatientPhone = PatientPhone
                    });
                    
                }
                
                return PatientDetails;
            }
        }
    }
    

    I've used this type of setup frequently in the past to simplify the data layer and make it easily consumable by other applications.  This has worked fine until trying to fit this into MVC.  In other words, its not new code.

    Monday, January 29, 2018 3:43 PM
  • User475983607 posted

    I've used this type of setup frequently in the past to simplify the data layer and make it easily consumable by other applications.  This has worked fine until trying to fit this into MVC.  In other words, its not new code.

    There is no easy way to use this design in MVC. 

    Monday, January 29, 2018 6:58 PM
  • User1122355199 posted

    Which part.  The model in the class library or the method of populating the data?  

    Monday, January 29, 2018 7:10 PM
  • User475983607 posted

    kmcnet

    Which part.  The model in the class library or the method of populating the data?  

    Both... I can get the data to display but it's very confusing.

    I wrapped a layer around the tblPtmstr1 class which maps to a POCO and MVC likes POCOs.   Modifying tblPtmstr1 to handle CRUD was odd and confusing.  In the end it is easier and quicker to build a traditional Data Access layer. 

    Monday, January 29, 2018 7:38 PM
  • User1122355199 posted

    Wow.  So basically rebuild everything into the MVC project and maintain two sets of code?

    Monday, January 29, 2018 8:36 PM
  • User475983607 posted

    Wow.  So basically rebuild everything into the MVC project and maintain two sets of code?

    I built a wrapper around the KidsMedicalDB_MVC.tblPtmstr1. The wrapper hides the complexity of mapping tblPtmstr1 to a simple POCO list.  There are two version of the wrapper the first does not maintain state and you can run fetch data many times the second caches the results.  These are not production version of code just ideas.

    Be aware that I had to fix syntax errors in KidsMedicalDB_MVC.tblPtmstr1 class as the posted code did not compile.

    Wrapper

    namespace BusinessLayer
    {
        public class tblPtmstr1Wrapper
        {
            private KidsMedicalDB_MVC.tblPtmstr1 _db;
    
            public tblPtmstr1Wrapper()
            {
                _db = new KidsMedicalDB_MVC.tblPtmstr1();
            }
    
            public List<SharedPocos.Patient> GetPatientDetailsByMrNumber(string MRNumber)
            {
                if(_db.PatientDetails.Count() > 0)
                {
                    _db.PatientDetails.Clear();
                }
                _db.GetPatientDetails(MRNumber);
    
                //Projection to convert List<tblPtmstr1> to List<SharedModels.Patient>
                return (from p in _db.PatientDetails
                             select new SharedPocos.Patient()
                             {
                                 PatientID = p.PatientID,
                                 PatientLastName = p.PatientLastName,
                                 PatientFirstName = p.PatientFirstName,
                                 PatientMiddleName = p.PatientMiddleName,
                                 PatientAddress = p.PatientAddress,
                                 PatientAddress2 = p.PatientAddress2,
                                 PatientCity = p.PatientCity,
                                 PatientState = p.PatientState,
                                 PatientZip = p.PatientZip,
                                 PatientPhone = p.PatientPhone
                             }).ToList();
            }
    
        }
    }

    Shared POCO.

    namespace SharedPocos
    {
        public class Patient
        {
            public int PatientID { get; set; }
            public string PatientLastName { get; set; }
            public string PatientFirstName { get; set; }
            public string PatientMiddleName { get; set; }
            public string PatientAddress { get; set; }
            public string PatientAddress2 { get; set; }
            public string PatientCity { get; set; }
            public string PatientState { get; set; }
            public string PatientZip { get; set; }
            public string PatientPhone { get; set; }
        }
    }
    

    The implementation is straight forward.

            static void Main(string[] args)
            {
                BusinessLayer.tblPtmstr1Wrapper dlWrapper = new BusinessLayer.tblPtmstr1Wrapper();
                List<SharedPocos.Patient> details = dlWrapper.GetPatientDetailsByMrNumber("1234");
    
                foreach (SharedPocos.Patient detail in details)
                {
                    Console.WriteLine(detail.PatientID);
                }
    
            }

    Here is another version of the wrapper depending on how you wish to cache data.

    namespace BusinessLayer
    {
        public class tblPtmstr1Wrapper
        {
            private KidsMedicalDB_MVC.tblPtmstr1 _db;
            private string _MRNumber;
            private List<SharedPocos.Patient> _patients;
    
            public tblPtmstr1Wrapper(string MRNumber)
            {
                _db = new KidsMedicalDB_MVC.tblPtmstr1();
                _MRNumber = MRNumber;
            }
    
            //Expose only the List<tblPtmstr1> PatientDetails property
            public List<SharedPocos.Patient> PatientDetails
            {
                get
                {
                    if (_patients == null)
                    {
                        //Invoke DB fetch
                        _db.GetPatientDetails(_MRNumber);
    
                        //Projection to convert List<tblPtmstr1> to List<SharedModels.Patient>
                        _patients = (from p in _db.PatientDetails
                                     select new SharedPocos.Patient()
                                     {
                                         PatientID = p.PatientID,
                                         PatientLastName = p.PatientLastName,
                                         PatientFirstName = p.PatientFirstName,
                                         PatientMiddleName = p.PatientMiddleName,
                                         PatientAddress = p.PatientAddress,
                                         PatientAddress2 = p.PatientAddress2,
                                         PatientCity = p.PatientCity,
                                         PatientState = p.PatientState,
                                         PatientZip = p.PatientZip,
                                         PatientPhone = p.PatientPhone
                                     }).ToList();
                    }
    
                    return _patients;
    
    
                }
            }
        }
    }

    Implementation

            static void Main(string[] args)
            {
                BusinessLayer.tblPtmstr1Wrapper dlWrapper = new BusinessLayer.tblPtmstr1Wrapper("1234");
                List<SharedPocos.Patient> details = dlWrapper.PatientDetails;
    
                foreach (SharedPocos.Patient detail in details)
                {
                    Console.WriteLine(detail.PatientID);
                }
    
            }

    Monday, January 29, 2018 10:22 PM
  • User303363814 posted

    Whether your code is in classes within the MVC project or in classes in a separate project is pretty much irrelevant.  (Personally, I always put my domain model in a separate project and the tests of that model in yet another project.  It doesn't really matter, it is a matter of style)

    You say 'Lets' move past the notion of code not being executed as I have verified data is being returned'.  That's good progress.

    So when you single step through the code that is giving you problems which is the first line that gives a result that you do not expect?  Show that exact code.  Tell us what you expect to happen and tell us what actually happens.

    Thursday, February 1, 2018 2:08 AM