Map entities to many-to-many junction table in EF 4.5 - c#

At the moment I’m mapping my existing DB tables to new EF 4.5 model via Fluent Api. I’ve got a questing on how to map following db structure to classes.
Students(pk Id...)
Courses (pk Id...)
Students_Courses (pk Id, fk StudentId, fk CourseId)
Comments (pk Id, fk Students_Courses Id, comment, dateposted...)
The idea is that I may have many reviews per student_course pair. What is the best way to represent my classes in this scenario?
The problem here is that I’ll probably need to map Comment entity to Students_Courses table and somehow determine to which Student and Course (in terms of classes) this comment belongs.
Any suggestions on the design?
Thanks!

Maybe you'd like to use Entity Framework Power Tools to reverse-engineer your data model into a "code -first" model with DbContext API.
You will see that something like a StudentCourse class will be generated that looks like this:
public class StudentCourse
{
public StudentCourse()
{
this.Comments = new List<Comment>();
}
public int StudentCourseId { get; set; }
public int StudentId { get; set; }
public int CourseId { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
and Comment looking like this:
public class Comment
{
public int CommentId { get; set; }
public int StudentCourseId { get; set; }
public virtual StudentCourse StudentCourse { get; set; }
...
}
So comments are related with students and courses through StudentCourse

Related

Create a foreign key on a table in entity framework core that references the identity user table

I am trying to create relationships from the AspNetUsers table autogenerated by AspNet Identity to tables created by myself. Ex. Table A has a UserId column set to nvarchar(128) and I want it to relate to the UserId column the AspNet Users table. This is an Asp.Net MVC web app.
first I have some considerations you should not use nvarchar as FK much less as UserId because it is much more performant for a structural database like SQL to index but if you are using non-structural ignore this ...
good now for your solution see relationships between tables must be done through a ConfigMap where the entityFramework understands the relationships between objects and map them to the database I will give you an example:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure StudentId as FK for StudentAddress
modelBuilder.Entity<Student>()
.HasRequired(s => s.Address)
.WithRequiredPrincipal(ad => ad.Student);
}
consider these classes as relation objects
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public virtual StudentAddress Address { get; set; }
}
public class StudentAddress
{
[ForeignKey("Student")]
public int StudentAddressId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public int Zipcode { get; set; }
public string State { get; set; }
public string Country { get; set; }
public virtual Student Student { get; set; }
}
see that the mapping on how the relationship should occur was done here OnModelCreating
there is another way to do it by making a configuration class for each object/table in the database that way it would be more organized
class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
public void Configure(EntityTypeBuilder<Customer> builder)
{
builder.HasKey(c => c.AlternateKey);
builder.Property(c => c.Name).HasMaxLength(200);
}
}
example:
EF Core Mapping EntityTypeConfiguration
I can also put the entityFramework documentation as a good guide for its development
1:1
https://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx
1:N
https://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx
N:N
https://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
I really hope I helped with your question.
another point did not comment but you should study about migrations and use them in your project to version your changes in the database
https://www.entityframeworktutorial.net/efcore/entity-framework-core-migration.aspx#:~:text=Migration%20is%20a%20way%20to,on%20the%20EF%20Core%20model.

Issue with navigation properties in EntityFramework 6

If I have a Course class, that has a collection of students (ICollection<Person>) as follows:
public class Person
{
public Person()
{
this.Courses = new HashSet<Course>();
}
public int PersonId { get; set; }
[Required]
public string PersonName { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
public class Course
{
public Course()
{
this.Students = new HashSet<Person>();
}
public int CourseId { get; set; }
public string CourseName { get; set; }
public virtual ICollection<Person> Students { get; set; }
}
I end up with this structure in the database (as expected):
(note the PersonCourses table)
However, in my example, I also want to add an instructor to the course.
This instructor is also a Person, who can attend courses just like everyone else, so I adjust the above classes as shown below:
public class Person
{
public Person()
{
this.Courses = new HashSet<Course>();
}
public int PersonId { get; set; }
[Required]
public string PersonName { get; set; }
public virtual ICollection<Course> Courses { get; set; }
public virtual ICollection<Course> InstructedCourses { get; set; }
}
public class Course
{
public Course()
{
this.Students = new HashSet<Person>();
}
public int CourseId { get; set; }
public string CourseName { get; set; }
public virtual ICollection<Person> Students { get; set; }
public virtual Person Instructor { get; set; }
}
What I was expecting to see is the same database structure as above, but with an additional table created that linked a person to many courses.
However, what I got was this:
(Note that the PersonCourses table has gone)
What I was Expecting/Hoping to see was similar to this:
It's probably worth stating that the reason I've not got a separate Instructor/Person class is that I'm expecting that any Person can create a course, and thus become an instructor for that course.
Firstly - Is this possible to achieve via code-first in EF? I'm assuming so..
Secondly - What is it I'm doing wrong?
Thirdly - Is it the weekend yet?
All help appreciated :)
This is one reason I don't like / recommend code-first. It looks like EF got confused with the second InstructedCourses collection and instead just set up the instructor reference back from the course, though it seems to have just made the students collection a 1-to-many as well.
I would seriously consider either:
A) changing you domain to define an Instructor entity vs. Student entity
or
B) Do schema first with the proper EF mappings to the tables you want.
I don't think any DBA is going to want to see things like course_personId / Person_personId throughout the schema that they are one day going to need to support and optimize.
Instructors and Students can extend a base "Person" class with either table per entity or an identifier. Course to instructor and course to student relationships can then be defined more clearly. The limitation would be if you wanted the same "person" to be able to be referenced as both an instructor and a student.

Multiple foreign key relationships for one record in asp.net mvc, code-first

I have a very simple question. I am new to ASP.NET MVC and very much confused about relationships while following code-first technique.
I have two model classes. I want to describe it as one person can have many courses.
public class Person
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PersonId { get; set; }
}
public class Course
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CourseId { get; set; }
// public virtual ICollection<Course> Courses{ get; set; }
/* I removed above line from model because it was not creating any Course Field in Db table of Person and added a third table */
}
In order to make a relationship I created another model class that contains Id of persons and repeating Id's of the course
public class ModelJoin
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ModelJoinId { get; set; }
[ForeignKey("Person")]
public int PersonId { get; set; }
public virtual Person Person{ get; set; }
//One to many relationships
public virtual ICollection<Course> Courses{ get; set; }
}
So model join will have only two properties. I want to ask how we achieve this in a best way.
Value of courses will always be null so we can not add any course in it. Where in the code we will assign it a object?
There are a lot of questions on stackoverflow but no one describes it from scratch.
Is there any tutorial for add update delete tables with foreign keys.
Any help would be appreciated.
I think you need many to many relationship as one student can be enrolled for many courses and one course can be taken by many students.
Look at this:
http://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
The course collection should be in the Person class, try this :
public class Person
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PersonId { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
public class Course
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CourseId { get; set; }
}
So for example if you want to add a person with a course.
var person = new Person();
var courses = new List<Course>();
courses.Add(new Course());
person.Courses = courses;
dbContext.Persons.Add(person);
dbContext.SaveChanges();

EntityFramework Add to Many-To-Many

I have a Vacation and a list of Countries. I whish to bind these together using a many-to-many relationship. I have a code-first Vacations model and Countries model. Both the individual tables aswell as the join table are successfully generated.
However, when I try to add a country to a vacation (or vice versa) the join table remains empty. I am able to successfully add the individual vacations aswell as the countries.
Models
public class Vacations
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int VacationId { get; set; }
public string ProductId { get; set; }
public string Name { get; set; }
public string Price { get; set; }
public virtual ICollection<Countries> Countries { get; set; }
public Vacations()
{
Countries = new List<Countries>();
}
}
public class Countries
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CountryID { get; set; }
public string CountryName { get; set; }
public virtual ICollection<Vacations> Vacations { get; set; }
public Countries()
{
Vacations = new List<Vacations>();
}
}
public class MyContext : DbContext
{
public MyContext()
: base("myconn")
{
}
public DbSet<Vacations> Vacations { get; set; }
public DbSet<Countries> Countries { get; set; }
}
Insert the Vacation
Vacations vacation = database.Vacations.Add(new Vacations
{
Name = vacationData.Name,
Description = vacationData.Description,
});
database.SaveChanges();
// to make sure the key is in the database to refrence
foreach (string country in AllMyCountries)
{
Countries countries = database.Countries.Add(new Countries
{
CountryName = country
});
countries.Vacations.Add(vacation);
vacation.Countries.Add(countries);
}
database.SaveChanges();
I have also tried just adding to one entity, and adding more calls to SaveChanges() inbetween.
Interesting problem in that your sample code all looks perfectly okay. Infact, I put a quick test together around this code and Entity Framework created the mapping table vacationscountries as expected and populated it correctly.
Just on the off-change, can you confirm that you are looking in the mapping table created by Entity Framework and not a custom mapping table? The only reason I mention it is that theres no way (that I know of) to map a many-to-many relationship to a custom junction table using Data Annotations.
If thats not the case, then the next thing I would do is to trace out the sql being generated by Entity Framework - either using your native database tracing tooling (e.g. Sql Profiler), a third party tool like EFProf, or through a logging interceptor ( http://msdn.microsoft.com/en-gb/data/dn469464.aspx ). Hopefully that will give some lower-level insights into the problem.
I re-created your Models but made some adjustments that generate the same results. I manually created the junction table VacationsCountries with the following code:
public class VacationsCountries
{
[Key, Column(Order = 0)]
public int VacationId { get; set; }
public virtual Vacations Vacation { get; set; }
[Key, Column(Order = 1)]
public int CountryId { get; set; }
public virtual Countries Country { get; set; }
}
I also added this line of code to the MyContext class:
public DbSet<VacationsCountries> VacationsCountries { get; set; }
Instead of using:
countries.Vacations.Add(vacation);
vacation.Countries.Add(countries);
I use:
VacationsCountries vc = database.VacationsCountries.Add(new VacationsCountries
{
Country = countries,
Vacation = vacation
});
and then call database.SaveChanges();
I checked the database and the entries were added to the VacationsCountries table.

Am I building the wrong entities in MVC?

Goal. I have a "Gift" entity that describes what someone has to offer (babysitting, dog walking, etc) with a rating. And I want a "GiftCategory" entity that gives general category descriptive information (pets, sports, automotive, etc) for someone to search apon and then get all gift that have those categories. A "Gift" entity can have multiple "GiftCategory" entities associated with it. I want the ability to search for a category and pull out all "Gift" entities that have been created with those categories associated with them. Here is what I have so far but it doesn't seem to work with the entity first approach. Maybe I need another table that connects the two entities because currently the way the two tables are connected doesn't seem correct?
Gift entity:
public class Gift
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<GiftCategory> Categories { get; set; } // is this incorrect???
public int Rating { get; set; }
}
Category entity:
public class GiftCategory
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
The "GiftCategory" table that gets created creates a gift_id column that links the "GiftCategory" back to a gift (not what I want)!!!!
It seems like I would need to create a entity that connects the two entities? Something like:
public class ConnectGifts
{
public int Id { get; set; }
public string GiftId{ get; set; }
public string GiftCategoryID{ get; set; }
}
This way I can have multiple categories for a Gift, but the thing I don't understand is with entity first I really don't need this entity I just need what would be this table to get/query the "GiftCategory" entities for ids then get the gift ids to get all the gifts. So it seems like creating this entity is overkill? Is there a way to do it without creating a third table/entity ("ConnectGifts") with code first? Or am I not understanding that all entities are tables and all tables are entities? I'm also using linq-to-sql for all querying.
You're looking for a many-to-many relationship and can be defined as:
public class Gift
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<GiftCategory> Categories { get; set; } // is this incorrect???
public int Rating { get; set; }
}
public class GiftCategory
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Gift> Gifts { get; set; }
}
So each has a collection of the other. Gift has many Categories and Category had many Gifts. You could use a bridge table like you've done with ConnectGifts but it's not necessary with EF. Using just Gift and GiftCategory, EF will actually create the bridge table for you.

Categories

Resources