I have 2 tables Person and Student. Person has a 1-to-1 relationship with Student. The fields are:
Person
- ID
- FirstName
- LastName
Student
- PersonID
I also have 2 classes:
public class Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public int LastName { get; set; }
}
public class Student : Person
{
}
I now need to create DbSets for them so I can access the tables. My question is, is it OK to create one DbSet for the Student (which would need splitting) or should I just create 2 DbSets. One for Person one for Student?
Related
I am new to Entity Framework Core, can any one help me how to insert the data in the following table.
Student Table
==============
StudentID Int
StudentName Varchar(50)
Class Table
===============
ClassID int
ClassName Varchar(50)
StudentClassXref
==================
StudentID int
ClassID Int
The relationship for the above tables will Student Table will have a Foreign key to Xref table only, same applies for the Class table.
There is no direct link between Student and Class table, so once I generated the POCO classes I got the above 3 tables and relationship with Student and Class Table refering only to Xref table.
So Now how to insert data in Student, Class and Xref table.
After saving the Values should be
Student
===========
1 xxxxx
Class
============
1 Maths
2 Science
Xref
===========
1 1
1 2
Can any one help me how to insert the data to these tables using EF core.
Thanks in advance.
My POCO Class
public partial class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public System.Collections.Generic.ICollection<StudentClasseXref> StudentClasseXrefs { get; set; }
public Equation()
{
StudentClasseXrefs = new System.Collections.Generic.List<StudentClasseXref>();
InitializePartial();
}
}
Classes POCO
public partial class Class
{
public int ClassId { get; set; }
public string ClassName { get; set; }
public System.Collections.Generic.ICollection<StudentClasseXref> StudentClasseXrefs { get; set; }
public Class()
{
StudentClasseXrefs = new System.Collections.Generic.List<StudentClasseXref>();
InitializePartial();
}
}
Xref POCO Class
public partial class StudentClassXref
{
public int StudentId { get; set; }
public int ClassId { get; set; }
public Student Student { get; set; }
public Class Class { get; set; }
}
I am new to entity framework and I am using code first approach to create entities using TPT inheritance.
My requirement is to create the entities as per the attached diagram where ID is PK for Customers table and FK for the AddressDetails and ContactDetails table. Based on the keys I also need to create the association and navigation properties for the entities. Table Diagram
In my code I have created entities as
public class Customer
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int ZipCode { get; set; }
public virtual ContactDetails ContactDetails { get; set; }
public virtual AddressDetails AddressDetails { get; set; }
}
[Table("ContactDetails")]
public class ContactDetails: Customer
{
public string MobileNo { get; set; }
public string EmailId { get; set; }
}
[Table("AddressDetails")]
public class AddressDetails: Customer
{
public string BillingAddress { get; set; }
public string DeliveryAddress { get; set; }
}
My question is, have I created the association and navigation properties correctly or do I need to add them in the ContactDetails and AddressDetails class as well? Also, when I run the code the entities are getting created in the database but for the Customer table there are 2 additional columns created as AddressDetails_Id(FK,int,null) and ContactDetails_Id(FK,int,null). I think they are created because of the navigation property but I do not need these columns in the database to be created. Also the values are always null in these two columns.
Any help would be appreciated. Thanks in advance.
I have 2 tables in different schemas:
Base.Person
ID
FirstName
LastName
Enrollment.Student
PersonID
StudentNo
This is related one-to-one.
Now in my DbContext, I want to have a DbSet named Students but I want its properties mapped to Person and Students. In particular, I want to get Person.ID, Person.FirstName, Person.LastName, Student.StudentNo mapped into my Student class.
The Student class is:
public class Student
{
public int ID { get; set;}
public string FirstName { get; set;}
public string MiddleName { get; set;}
public string StudentNo { get; set;}
}
One additional question that I'd like to ask which is not related to my problem above but it will be clearer to ask if the example above is present, in designing your DbContext, is DbContext intended to make the whole of the database available to you or is it ok just to expose what you want? For example, in my question above, I don't have a Person DbSet.
You cannot currently do this in EF 7 EF Core. However, you can model one to one relationships like this:
[Table("Student", Schema = "Enrollment")]
public class Student
{
[Key]
public string StudentNo { get; set; }
[ForeignKey("PersonId")]
public Person Person { get; set; }
[Column("PersonID")] // <-- if your db is case sensitive
public int PersonId { get; set; }
}
[Table("Person", Schema="Base")]
public class Person
{
// [Key] - not needed as EF conventions will set this as the "key"
[Column("ID")] // again, if case sensitive
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
// in code, use .Include to materialize dependent entities like so....
context.Students.Include(s => s.Person).Where(s => s.Person.FirstName == "Bob");
For more info on modeling, see https://docs.efproject.net/en/latest/modeling/relationships.html#one-to-one
Say I have this existing schema:
and have this domain mapping as follows:
public class SchoolContext : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Subject> Subjects { get; set; }
}
protected override OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().ToTable("People");
modelBuilder.Entity<Student>().ToTable("Students");
}
public abstract class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Student : Person
{
public int StudentId { get; set; }
public string Course { get; set; }
public ICollection<Subject> Subjects { get; set; }
}
public class Subject
{
public int SubjectId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int StudentId { get; set; }
}
And I was given a scenario that I need to query on the subject via PersonId, EF will throw me an exception saying "Invalid column name 'Student_PersonId'".
I understand EF can't see the FK well and I opted to make the Person class as a Base class since there's a chance that I'll have a Teachers table in which it is a Person as well.
Note that Student table need to have its own Primary Key and let's just say the schema was design with a relationship of:
Person -> Student (One-to-Zero or One relationship)
Student -> Subject (One-to-Many relationship)
Is there a way to fix this? Also note that if it's made using Code-First, EF will ommit StudentId on Students table and I do have an existing DB anyway
You should start off by reading this article about TPT in entity framework. Now you don't have a 'Student is a person' kind of relationship, and you'll have to change some things to your database for it to work.
Student's primary key should at the same time be the foreign key to your people table. Since student is a person, it has that database as its baseclass and the Student table should only contain specific properties for student. The properties by Person are inherited.
Person is your abstract base class. Every student, teacher... is a person which is why you can't have a DbSet of Student/teacher... They are persons, so DbSet<Person> is all you need.
You can't map Person to a table. If you really want TPT every person is also a teacher, student... A person alone shouldn't exist, so you shouldn't map it to a table. There's a reason the class is abstract, you can't have just a person. For example Person p = context.Students.FirstOrDefault(); is perfectly valid code for TPT.
That being said, if you think Person can have instances of his own (so certain persons don't have a derived class) you shouldn't opt for TPT and just work with the foreign key to the person table like you do now. If you do want to use TPT you'll have to make above adjustments.
I've used code first for linking to an existing database via TPT inheritance here in this code i have one base class called Person and 2 subclasses called Student and Teacher and both Student and Teacher class inherit from Person class
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Student : Person
{
public int? Payment { get; set; }
}
public class Teacher : Person
{
public int Wage { get; set; }
}
and this is my Context Class
public class PersonContext : DbContext
{
public PersonContext()
: base("TPT")
{
Database.SetInitializer<PersonContext>(null);
}
public DbSet<Person> Persons { get; set; }
public DbSet<Student> Students { get; set; }
public DbSet<Teacher> Teachers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().ToTable("Persons");
modelBuilder.Entity<Teacher>().ToTable("Teachers");
modelBuilder.Entity<Student>().ToTable("Students");
}
}
I've inserted a record with FirstName and LastName and saved it in the Persons table, via adding a simple Person instance to the context. It's because I don't know the type of the person in that time. In another list, operator recognizes the record, and tries to add extra data to it (for example adding Payment for students). What should I do now? If I get that person's record and cast it to Student class and try to update it, I'll get this error:
'TablePerTypeInheritance.Models.Person' does not contain a definition
for 'Payment' and no extension method 'Payment' accepting a first
argument of type 'TablePerTypeInheritance.Models.Person' could be
found (are you missing a using directive or an assembly reference?)
You save a record of the type Person, so it will be always retrieved from the DB as Person.
In C# you can't cast a base class to a derived class. Such operation is invalid.
var person = new Person();
var student = (Student)Person; // doesn't compile
If you want to change the type of the record, you have to create a new object of the desired type.
var person = context.Persons.Find(1);
var student = new Student() {
FirstName = person.FirstName,
LastName = pesron.LastName
};
context.Persons.Remove(person);
context.Student.Add(student);
hi my friend you have to use own sql command to do it.
var id = new SqlParameter("#id", std.StudentId);
var rate = new SqlParameter("#rate", std.Rate);
contex.Database.ExecuteSqlCommand("insert into ExcelentSudents values (#id,#rate)", id, rate);