'EF Core - Repository, Model or View Model
To start, here are my classes:
public class Name
{
public int NameId {get;set;}
public string Value {get;set;}
[ForeignKey("Name_NameId")]
public ICollection<PersonName> PersonsName {get;set;}
}
public class NameType
{
public int NameTypeId {get;set;}
public string Value {get;set;}
[ForeignKey("NameType_NameTypeId")]
public ICollection<PersonName> PersonsName {get;set;}
}
public class Person
{
public int PersonId {get;set;}
public string Suffix {get;set;}
public datetime DateOfBirth {get;set;}
[ForeignKey("Person_PersonId")]
public ICollection<PersonName> PersonsName {get;set;}
}
public class PersonName
{
public int Person_PersonId {get;set;}
public int Name_NameId {get;set;}
public int NameType_NameTypeId {get;set;}
public int Order {get;set;}
}
Ideally, when accessing the Person class, I'd like to be able to call a function (or property) that could pull the person's full name from the PersonName repository. However, I'm not quite sure how to do that. For an example of data in these tables:
NameId Value
1 John
2 Jacob
3 Jingleheimer
4 Schmidt
NameTypeId Value
1 First Name
2 Middle Name
3 Last Name
4 Nickname
PersonId Suffix DateOfBirth
1 01/01/1900
Person_PersonId Name_NameId NameType_NameTypeId Order
1 1 1 0
1 2 2 0
1 3 2 1
1 4 3 0
So in the Person class, I'd like to have a function/property like GetFullName()/FullName where it would return "John Jacomb Jingleheimer Schmidt". I've been working through a tutorial from scratch and after making each class they then make an interface, mockrepository and are working on a db repository. However, I'd like to pass the information into a view via a View Model, but I'm not sure how to tie the class to the repository, etc. Is there anyone that can either point me to a tutorial that can explain that best or spell it out for me? Thanks.
Solution 1:[1]
In my opinion, your tables are too complicated. The draw back is that you have to join so many tables just to get someones' Full Name... and because of all the joins you would potentially face performance issues... this code would be hard to understand and maintain by other developers.
So, I know I am not answering your question directly, but I would recommend you to simplify your table design.
Why not using a simple table like:
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set;}
public string MiddleName { get; set;}
public string LastName { get; set; }
public string NickName { get; set; }
public string Suffix { get; set; }
public datetime DateOfBirth { get; set; }
// it is a lot easier to implement GetFullName() method here than joining so many tables
public string GetFullName()
{
retun FirstName + " " + MidleName + " " + LastName;
}
}
I am really struggling to understand your last table: PersonName
public class PersonName
{
public int Person_PersonId { get; set; }
public int Name_NameId { get; set; }
public int NameType_NameTypeId { get; set; }
public int Order { get; set; } // <-- Why putting Order in PersonName?
}
To me, Order is not a logical column in PersonName's table... I don't fully understand your design and I could be totally wrong... but to me, it feels like an over-engineered design.
Solution 2:[2]
I hope I understood your questions correctly
I made some assumptions though
I used your classes to construct a database and queried the database so the other tables are linked by relationship
Assuming you are passing the id of the person, and also assuming that the dbcontext is available and instantiated inside of the class, then call GetFullName
public string GetPersonById(int personId)
{
var person = db_context.PersonNames.FirstOrDefault(m => m.Person_PersonId == personId);
//did not check for null here
var name = person.Person.PersonNames.ToList();
var fullname = "";
name.ForEach(m => fulname += m.Name.Value + " ");
return fullname;
}
public virtual string GetFullName
{
get { return GetPersonById(PersonId); }// the person id passed, the class if instantiated can call this instance PersonId
set { ; }
}
Also you can get data the from the database into the models you have and the method works fine. passing them from the db give you the relationship ability and Razor Engine can be of great help in the View, but
To get the data you will need to pull out the data one after the other and store in a list.
public void UseModel()
{
var people = _context.People.ToList();
var names = _context.Names.ToList();
var name_types = _context.NameTypes.ToList();
List<PersonModel> ps = new List<PersonModel>();
people.ForEach(m =>
{
ps.Add(new PersonModel
{
PersonId = m.PersonId,
Suffix = m.Suffix,
DateOfBirth = m.DateOfBirth,
PersonsName = null//I suggest you use mapping here see https://stackoverflow.com/questions/16118085/best-practices-for-mapping-one-object-to-another
//use mapping to map the list or use a fooloop to construct it before this declaration and assign it here
});
});
//do for names and name_types
}
You can also pass this data to the View as an object PersonName that has all
Solution 3:[3]
To map your view model. You can use like that.
public class PersonDTO
{
public int PersonId { get; set; }
public string FirstName { get; set;}
public string MiddleName { get; set;}
public string LastName { get; set; }
public string NickName { get; set; }
public string Suffix { get; set; }
public datetime DateOfBirth { get; set; }
public string GetFullName()
{
retun FirstName + " " + MidleName + " " + LastName;
}
}
To Map FirstName , MiddleName , LastName , NickName. You can Use.
public void MapToPersonDTO(){
var selectedPerson = _context.Person.FirstOrDefault(m => m.PersonId == 1);
var personDto = new PersonDTO(){
FirstName = _context.Name.FirstOrDefault(n=>n.NameId == selectedPerson.PersonsName.FirstOrDefault(f=>f.NameType_NameTypeId == 1)).Value,
MiddleName= _context.Name.FirstOrDefault(n=>n.NameId == selectedPerson.PersonsName.FirstOrDefault(f=>f.NameType_NameTypeId == 2)).Value,
LastName = _context.Name.FirstOrDefault(n=>n.NameId == selectedPerson.PersonsName.FirstOrDefault(f=>f.NameType_NameTypeId == 3)).Value,
NickName = _context.Name.FirstOrDefault(n=>n.NameId == selectedPerson.PersonsName.FirstOrDefault(f=>f.NameType_NameTypeId == 4)).Value,
};
}
Solution 4:[4]
I am also working on this. My inspiration is the show "The First 48" on cable TV, where the "police" will have a name in their database compiling a file on an individual long before they have a person to tie to the events. Or Shawn Corey Carter takes on the name J-Zee. Or how about this one, Prince Rogers Nelson, his performing career he is known as Prince then he changed his name to a Logo. Add a column for that one. Whenever I see a suggestion to not strive for the complex, just make it simple. I always think, how is that going to represent those scenarios?
but I see the "PersonName" implementation like this given the capabilities of EF and EF Core.
public abstract class PeopleName
{
public PeopleName()
{
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[ForeignKey("Person"), Required, Column(Order = 1)]
public long PersonId { get; set; }
[ForeignKey("Name"), Required, Column(Order = 2)]
public long NameId { get; set; }
public EnumNameType NameType { get; set; }
public byte NameOrder { get; set; }
public virtual Person? Person { get; set; } = new Person();
public virtual Name? Name { get; set; } = new Name();
}
public class FirstName : PeopleName
{
[Required]
public new EnumNameType NameType { get; set; } =
EnumNameType.FirstName;
}
public class LastName : PeopleName
{
}
public class FullName : PeopleName
{
}
public class Alias : PeopleName
{
}
public class MiddleName : PeopleName
{
}
public class MiddleInitial : PeopleName
{
}
The DTO I am hoping could be done along this line. I am hoping someone will show us how to load it once and have the values delineated among the properties.
public class PersonDTO
{
public int PersonId { get; set; }
public string? FirstName
{
get
{
var names = NamesLink.OfType<FirstName>().ToList();
if (names.Any())
{
foreach (FirstName? fn in names)
{
firstName = fn.Name.NameString;
}
}
return firstName;
}
set
{
if (value != null)
{
var name = new Name { NameString = value };
var pn = new FirstName { Name = name };
NamesLink.Add(pn);
firstName = value;
}
}
}
private string? firstName;
public string? LastName
{
get
{
var names = NamesLink.OfType<LastName>().ToList();
if (!names.Any())
{
foreach (LastName fn in names)
{
lastName = fn.Name.NameString;
}
}
return lastName;
}
set
{
if (value != null)
{
var name = new Name { NameString = value };
var ln = new LastName { Name = name };
NamesLink.Add(new LastName { Name = name });
NamesLink.Add(ln);
lastName = value;
}
}
}
private string? lastName;
public DateTime DateOfBirth { get; set; }
public string GetFullName()
{
return FirstName + " " + LastName;
}
public virtual ICollection<PeopleName> NamesLink { get; set; } = new Collection<PeopleName>();
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | Yigit Tanriverdi |
| Solution 4 | ruffone |
