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.
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;
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.
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.
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.
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.
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?
kmcnet
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>.
kmcnet
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?
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.
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.
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.
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).
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)
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.
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.
PaulTheSmith
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.
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.
mgebhard
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.
mgebhard
Yours is a very simple problem to solve though. Create a class library project,
Which I have done:
mgebhard
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; }
}
}
}
mgebhard
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; }
}
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.
Perhaps you have hit the nail on the head with my lack of understanding.
mgebhard
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.
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.
kmcnet
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.
kmcnet
within each viewmodel that requires it, then populate it within the controller through some type method (either ADO or returning a List<Of.
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?
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; }
}
}
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.
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.
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.
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?
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.
Part 2. I have a method that receives a PatientID and returns a List<ExternalClass.tblPtmstr1>.
Can you explain what you mean by "setup"?
kmcnet
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.
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?
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.
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.
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.
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; }
}
}
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.
Member
321 Points
1714 Posts
Setting Class Value Equal to List
Jan 25, 2018 12:31 AM|kmcnet|LINK
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:
The class I am trying to populate looks like:
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.
All-Star
50841 Points
9895 Posts
Re: Setting Class Value Equal to List
Jan 25, 2018 12:42 AM|A2H|LINK
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
Aje
My Blog | Dotnet Funda
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 25, 2018 12:59 AM|kmcnet|LINK
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.
Participant
1620 Points
927 Posts
Re: Setting Class Value Equal to List
Jan 25, 2018 06:37 AM|PaulTheSmith|LINK
Does GetPatientDetails("5732") actually return anything? Have you checked with the debugger?
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 25, 2018 12:07 PM|kmcnet|LINK
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.
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 25, 2018 08:01 PM|kmcnet|LINK
I have definitely verified the list of 1 record is created and returned. The code is failing at:
Oddly, I have tried placing this in a
but it seems to fall right through block without throwing any exceptions.
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 25, 2018 09:52 PM|mgebhard|LINK
A console example that hopefully explains how to structure the code.
Shared Model Layer
Data Access Layer
Console app
Edit: Copy error, missed the data access namespace.
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 27, 2018 02:48 AM|kmcnet|LINK
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:
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.
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 27, 2018 02:00 PM|mgebhard|LINK
The problem you are trying to solve is not clear.
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?
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>.
I think this last statement is where the confusion is. Can you show us the source code for myNodel.tblPtmstr1?
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 27, 2018 05:34 PM|kmcnet|LINK
Thanks for the response. Code for myModel.tblPtmstr1:
The code for the model in the external class:
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:
Then I tried modifying PatientDb, adding:
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.
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 27, 2018 10:12 PM|mgebhard|LINK
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.
Let's say we want to create a class named Table. It might look like this.
Or like this depending on what kind of table we're talking about.
This is where a namespace comes in.
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.
Participant
1620 Points
927 Posts
Re: Setting Class Value Equal to List
Jan 27, 2018 10:50 PM|PaulTheSmith|LINK
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)
Participant
1620 Points
927 Posts
Re: Setting Class Value Equal to List
Jan 27, 2018 11:14 PM|PaulTheSmith|LINK
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
Don't repeat yourself. The first piece of code should be
(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.
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 28, 2018 12:41 AM|kmcnet|LINK
Thanks for the response.
Done.
Done.
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.
Participant
1620 Points
927 Posts
Re: Setting Class Value Equal to List
Jan 28, 2018 12:54 AM|PaulTheSmith|LINK
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.
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 28, 2018 05:56 PM|kmcnet|LINK
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.
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.
Which I have done:
Using your example, I made these modifications:
And this is where I fall apart:
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:
within the SharedModelLayer.
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 28, 2018 06:48 PM|mgebhard|LINK
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.
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.
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 28, 2018 07:45 PM|kmcnet|LINK
Perhaps you have hit the nail on the head with my lack of understanding.
I assume by nested types, you are referring to
Perhaps, I only need to add:
within each viewmodel that requires it, then populate it within the controller through some type method (either ADO or returning a List<Of.
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 28, 2018 08:02 PM|mgebhard|LINK
No, this is were you are using nested types.
C# programming guide that explains nested types.
I don't see any reason to encapsulate a single List<T> within a class.
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
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 28, 2018 08:35 PM|kmcnet|LINK
Thanks for the response.
But this is the code you supplied in your example. See above. Why since you're implying it's not necessary?
Where?
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 28, 2018 08:52 PM|mgebhard|LINK
The demo code does NOT have nested typed. You added that bit and that's why I asked.
Demo Code
The whole thing.
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 28, 2018 11:44 PM|kmcnet|LINK
Thanks again for the response. Your first reply to this post:
Perhaps I misunderstand, but the only code I added to the SharedModelLayer was:
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:
At the hear of my conundrum is my understanding the partial view will require something like:
to populate this partial view. Obviously, if the viewmodel changed, the partiel view won't render.
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 12:58 AM|mgebhard|LINK
I provided two working examples that handle steps 1-3. I'm not sure what else I can do for you.
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 01:23 AM|kmcnet|LINK
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:
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.
Participant
1620 Points
927 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 05:53 AM|PaulTheSmith|LINK
But your code is not even being executed .... changing code that does not run will not alter anything.
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 11:58 AM|mgebhard|LINK
Something is not right with your understanding of the demo code.
What is an "external class model" and why is an "external class model" needed in your design?
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 12:29 PM|kmcnet|LINK
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:
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.
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 12:46 PM|mgebhard|LINK
Can you explain what you mean by "setup"?
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
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 01:56 PM|kmcnet|LINK
I think I've been pretty clear that this is an external class library.
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 02:05 PM|kmcnet|LINK
Let me rephrase for clarity, that this is a class library outside of the MVC project that will be referenced by the project.
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 02:41 PM|mgebhard|LINK
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.
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>.
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.
And the ViewModel to this. Where the return types equals the property type similar to the demo code.
I'm guessing that you really want this though.
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?
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 03:43 PM|kmcnet|LINK
Here is the entire class:
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.
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 06:58 PM|mgebhard|LINK
There is no easy way to use this design in MVC.
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 07:10 PM|kmcnet|LINK
Which part. The model in the class library or the method of populating the data?
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 07:38 PM|mgebhard|LINK
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.
Member
321 Points
1714 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 08:36 PM|kmcnet|LINK
Wow. So basically rebuild everything into the MVC project and maintain two sets of code?
All-Star
52971 Points
23571 Posts
Re: Setting Class Value Equal to List
Jan 29, 2018 10:22 PM|mgebhard|LINK
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
Shared POCO.
The implementation is straight forward.
Here is another version of the wrapper depending on how you wish to cache data.
Implementation
Participant
1620 Points
927 Posts
Re: Setting Class Value Equal to List
Feb 01, 2018 02:08 AM|PaulTheSmith|LINK
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.