These are my classes.
public class Teacher
{
public Teacher()
{
this.isPassive = false;
}
public int ID { get; set; }
public Nullable<int> LessonID { get; set; }
//Navigation Property
public virtual Lesson Lesson { get; set; }
}
public class Lesson
{
public int ID { get; set; }
public string Name { get; set; }
}
Below are the codes I mapped.
public TeacherMap()
{
HasKey(t => t.ID).Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
//Relationship
HasOptional(t => t.Lesson)
.WithMany()
.HasForeignKey(t => t.LessonID);
}
These are my classes and teacher classes. A teacher should have a lesson and a lesson must have a teacher. How should I do this mapping?
you should have a relation one to many , for example a lesson can have one or many teacher you can use this code :
public class Teacher
{
public Teacher()
{
this.isPassive = false;
}
public int ID { get; set; }
public Nullable<int> LessonID { get; set; }
[InverseProperty("Teachers")]
[ForeignKey("LessonID")]
public virtual Lesson Lesson { get; set; }
}
public class Lesson
{
public int ID { get; set; }
public string Name { get; set; }
[InverseProperty("Lesson")]
public virtual ICollection<Teacher> Teachers { get; set;}
}
for this secenario you dont need use fluent api.
UPDATE :
for one to one relation :
public class Teacher
{
public Teacher()
{
this.isPassive = false;
}
public int ID { get; set; }
public virtual Lesson Lesson { get; set; }
}
public class Lesson
{
[Key, ForeignKey("Teacher")]
public int ID { get; set; }
public string Name { get; set; }
public virtual Teacher Teacher { get; set;}
}
For more information see this .
Related
Say if I have the classic example of Student and Courses. A student can have many courses and course can have many students.
How do I make the middle table in EF 6 code if I wanted to add an extra field on the many table part?
Do I just make in code another class and then hook it up somehow?
DB Context
public class MyContext : DbContext
{
public MyContext (string nameOrConnectionString) : base(nameOrConnectionString)
{
// this.Configuration.ProxyCreationEnabled = false;
Database.SetInitializer(new CreateDatabaseIfNotExists<OSPContext>());
}
public DbSet<Student> Students { get; set; }
public DbSet<Course> Courses { get; set; }
public DbSet<StudentCourse> StudentCourses { get; set; }
}
public class StudentCourse
{
[Key]
public Guid StudentCourseId { get; set; }
public Guid StudentId { get; set; }
[ForeignKey("StudentId")]
public virtual Student Student { get; set; } // Include this so you can access it later
public Guid CourseId { get; set; }
[ForeignKey("CourseId")]
public virtual Course Course { get; set; }
public int Permissions { get; set; }
}
public class Course
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Student> Students { get; set; } = new >();
}
public class Student
{
[Key]
public Guid Id { get; set; }
public string Email { get; set; }
public virtual ICollection<Course> Courses { get; set; } = new List<Course>();
}
Given you are code first I would do something like the following.
public class Student
{
[Key]
public int StudentId { get; set; }
public string Name { get; set; }
public List<StudentCourse> Courses { get; set; } // So you can access Courses for a student
}
public class Course
{
[Key]
public int CourseId { get; set; }
public string Name { get; set; }
public List<StudentCourse> Students { get; set; }
}
public class StudentCourse
{
[Key]
public int StudentCourseId { get; set; }
public int StudentId { get; set; }
[ForeignKey("StudentId")]
public Student Student { get; set; } // Include this so you can access it later
public int CourseId { get; set; }
[ForeignKey("CourseId")]
public Course Course { get; set; }
}
EDIT: Wanted to note relationships are established with Data Attributes, you could also use EF Fluent API to establish your relationships. The properties will look the same, but without the [ForeignKey("")]
How could I map a custom many to many relationship with addition fields? In this case DateTime in Schedule.
Problem now is it creates a new table named StaffSchedules
public class Schedule
{
public int Id { get; set; }
public DateTime DateTime { get; set; }
public List<Staff> Staff { get; set; }
public int StaffId { get; set; }
public Patient Patient { get; set; }
public int PatientId { get; set; }
}
public class Staff
{
public int Id { get; set; }
public string FirstName { get; set; }
public List<Schedule> Schedules { get; set; }
}
...
public DbSet<Schedule> Schedules { get; set; }
public DbSet<Staff> Staff { get; set; }
Desired outcome:
Add a class like so:
public class StaffSchedule
{
public int StaffId { get; set; }
public int ScheduleId { get; set; }
public virtual Staff Staff { get; set; }
public virtual Schedule Schedule { get; set; }
public DateTime Date { get; set; }
}
Modify your Staff and Schedule classes:
public class Schedule
{
public int Id { get; set; }
//Other Fields
public ICollection<StaffSchedule> StaffSchedules { get; set; }
}
public class Staff
{
public int Id { get; set; }
//Other Fields
public ICollection<StaffSchedule> StaffSchedules { get; set; }
}
And lastly, in your context file (OnModelCreating method):
modelBuilder.Entity<Staff>().HasKey(x => x.Id);
modelBuilder.Entity<Schedule>().HasKey(x => x.Id);
modelBuilder.Entity<StaffSchedule>().HasKey(x =>
new
{
x.StaffId,
x.ScheduleId
});
modelBuilder.Entity<StaffSchedule>()
.HasRequired(x => x.Staff)
.WithMany(x => x.StaffSchedules)
.HasForeignKey(x => x.StaffId);
modelBuilder.Entity<StaffSchedule>()
.HasRequired(x => x.Schedule)
.WithMany(x => x.StaffSchedules)
.HasForeignKey(x => x.ScheduleId);
UPDATE:
Looks like you actually wanted this:
public class Patient
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Staff
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Schedule
{
public int Id { get; set; }
public DateTime Date { get; set; }
public int PatientId { get; set; }
public int StaffId { get; set; }
[ForeignKey("PatientId")]
public virtual Patient Patient { get; set; }
[ForeignKey("StaffId")]
public virtual Staff Staff { get; set; }
}
I kept getting this error
Invalid column name 'student_student_name'
Here is my class for my database context
public class CSdbConnectionString : DbContext
{
public CSdbConnectionString()
: base("CSdbConnectionString")
{ }
public DbSet<appointment> appointments { get; set; }
public DbSet<faculty> faculties { get; set; }
public DbSet<sched> scheds { get; set; }
public DbSet<student> students { get; set; }
}
My appointment class needs to inherit the values of the foreign key faculty and student
[Table("appointment")]
public class appointment
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int appointment_id { get; set; }
public string appointment_description { get; set; }
public int student_id { get; set; }
public int faculty_id { get; set; }
public virtual student student { get; set; }
public virtual faculty faculty { get; set; }
}
Here is my faculty class
[Table("faculty")]
public class faculty
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int faculty_id { get; set; }
public string faculty_name { get; set; }
public string faculty_lname { get; set; }
public string faculty_email { get; set; }
public string faculty_password { get; set; }
public string faculty_dept { get; set; }
}
Here is my student class
[Table("student")]
public class student
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public string student_name { get; set; }
public string student_lname { get; set; }
public string student_email { get; set; }
public string student_password { get; set; }
public string student_number { get; set; }
public string student_program { get; set; }
}
The faculty class is working fine. I can inherit the values in my view
#item.faculty.faculty_name
I also used public virtual faculty faculty { get; set; } in another class to inherit the faculty values and it worked fine. I did the same thing to inherit the values in student class and it kept saying invalid column name.
I've already searched many solution here in stackoverflow and what happen is it just keeps getting new errors.
I tried adding this to the parent class which will be the one inherited
public virtual ICollection<appointment> appointments { get; set; }
and added this code
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<appointment>()
.HasRequired(c => c.student)
.WithMany(p => p.appointments)
.HasForeignKey(c => c.student_id);
}
and still there are errors.
All I did for the faculty to be inherited was add this to the child class public virtual faculty faculty { get; set; } and now I am trying to do the same with student and I always have errors. Can someone help me?
Well, first thing: Your student class has a string as a PrimaryKey and your are mapping it to an int in your appointment class
public int student_id { get; set; }
try to change it and see if it works.
I have these two very simple classes.
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Group Group { get; set; }
}
public class Group
{
public int Id {get;set;}
public ICollection<Person> Teachers { get; set; }
public ICollection<Person> Students { get; set; }
}
I would like EF to keep Teachers seperated from Students however they both get jumbled into a Person table with no way to distinguish between them.
Any ideas?
There are two ways to do it;
first : use a tag or enums in the Person object
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Group Group { get; set; }
public bool IsFaculty { get; set; }
}
or
public enum PersonType { Teacher, Student };
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Group Group { get; set; }
public PersonType PropPersonType { get; set; }
}
second : work object oriented with inheritance. This method has my preference because it's easy to manage and expand if you want to expand it.
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Group Group { get; set; }
}
public class Student : Person
{
public int Year { get; set; }
// other student related fiels.
}
public class Teacher : Person
{
public List<Course> Courses { get; set; }
// other teacher related fields
}
Your Group is then
public class Group
{
public int Id {get;set;}
public ICollection<Teacher> Teachers { get; set; }
public ICollection<Student> Students { get; set; }
}
Separate in two different classes, and then inherit both of them with Person, because all the teachers and students are Persons, but not all Persons are teachers and students.
public class Person
{
}
public class Teacher : Person
{
}
public class Student : Person
{
}
I hope this helps
A little bit different case (when class is holding reference to two identical objects), but can be helpful:
public class Mission
{
//DB objects
public int Id { get; set; }
public int SourceLocationId {get; set}
public int DestinationLocationId {get; set}
//Virtual objects
public virtual Location SourceLocation { get; set; }
public virtual Location DestinationLocation { get; set; }
}
public class Location
{
//DB objects
public int Id {get;set;}
//Virtual objects
public virtual ICollection<Mission> SourceMissions { get; set; }
public virtual ICollection<Mission> DestinationMissions { get; set; }
}
Then all you need to do is bind it properly in OnModelCreating:
modelBuilder.Entity<Mission>()
.HasOptional(m => m.SourceLocation) //Optional or Required
.WithMany(sm => sm.SourceMissions)
.HasForeignKey(to => to.SourceLocationId);
modelBuilder.Entity<Mission>()
.HasOptional(m => m.DestinationLocation) //Optional or Required
.WithMany(sm => sm.DestinationMissions)
.HasForeignKey(to => to.DestinationLocationId);
I think you need some flag to distinguising them (I can't really belive you that can't). And after you can use TPH inheritance approach. See more info here and here.
To have Teachers and Students in two separate tables inherit from an abstract base:
public abstract class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Group Group { get; set; }
}
public class Student : Person
{
public int Year { get; set; }
// other student related fiels.
}
public class Teacher : Person
{
public List<Course> Courses { get; set; }
// other teacher related fields
}
public class Group
{
public int Id {get;set;}
public ICollection<Teacher> Teachers { get; set; }
public ICollection<Student> Students { get; set; }
}
Here's the problem. I have table User which have quite a few fields. What I want to do is split this table into multiple entities like this:
User
-> GeneralDetails
-> CommunicationDetails
-> Address
etc.
All goes well when extracting some fields from User into GeneralDetails. However, when I try to do the same thing for CommunicationDetails EF blows up and require to establish one-to-one relationship between GeneralDetails and CommunicationDetails.
Sample entities definition:
public class User {
public int UserId { get; set; }
public string SomeField1 { get; set; }
public int SomeField2 { get; set; }
public virtual GeneralDetails GeneralDetails { get; set; }
public virtual CommunicationDetails CommunicationDetails { get; set; }
public virtual Address Address { get; set; }
}
public class GeneralDetails {
[Key]
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public virtual User User { get;set; }
}
public class CommunicationDetails {
[Key]
public int UserId { get; set; }
public string Phone { get; set; }
public string DeviceToken { get; set; }
public virtual User User { get;set; }
}
public class Address {
[Key]
public int UserId { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string Street { get; set; }
public virtual User User { get;set; }
}
Sample mapping:
modelBuilder.Entity<User>().
HasRequired(user => user.GeneralDetails).
WithRequiredPrincipal(details => details.User);
modelBuilder.Entity<User>().
HasRequired(user => user.CommunicationDetails).
WithRequiredPrincipal(details => details.User);
modelBuilder.Entity<User>().
HasRequired(user => user.Address).
WithRequiredPrincipal(details => details.User);
modelBuilder.Entity<User>().ToTable("Users");
modelBuilder.Entity<GeneralDetails>().ToTable("Users");
modelBuilder.Entity<Address>().ToTable("Users");
Why on earth EF want this relationship? Is there any way this could be solved?
The correct way to actually do this is by Complex Types rather than entities. Its actually a more common problem than you think.
public class MyDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelbuilder.ComplexType<CommunicationDetails>();
modelbuilder.ComplexType<GeneralDetails>();
modelbuilder.ComplexType<Address>();
modelbuilder.Entity<User>().ToTable("Users");
}
}