Issue with many to many relationship in code first c# - c#

I am using entity framework code first for creating database in my project. I have defined many to many relationship between following two table.:
Student
Course
Fluent Api
modelBuilder.Entity<Student>().HasMany(e => e.Courses)
.WithMany(e => e.Students).Map(m =>
{
m.MapLeftKey("StudentId");
m.MapRightKey("CourseId");
m.ToTable("StudentCourse");
});
This will define a many to many relationship between Student and Course and will create a new table StudentCourse in the database.
Now i want to define a new relationship (that may be 1 to 1 OR 1 to many) between
StudentCource
Any other table
How can i do this with entity framework code first ??

What do you want is no possible without creating a own class (poco) for the StudentCourse
public class StudentCourse
{
public int Id {get;set;}
public Student Student {get; set;}
public Course Course {get; set;}
}
And then use fluent api to make the relationship between this three variables
modelBuilder.Entity<StudentCourse>()
.HasRequired(i => i.Student)
.WithMany(u => u.StudentCourses)
.HasForeignKey(i => i.StudentId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<StudentCourse>()
.HasRequired(i =>i.Course)
.WithMany(d =>d.StudentCourses)
.HasForeignKey(i => i.CourseId)
.WillCascadeOnDelete(false);
Where StudentCourses are the navigation properties in the student class and Course class
You can use the Id defined as primary key or use the foreign key of both tables as primary:
modelBuilder.Entity<StudentCourse>()
.HasKey(i => new {i.StudentId,i.CourseId });
In my opinion use the Id as primary key make you more simple the things for making relationships between StudentCourse and another table.

Related

Xamarin Forms, EF Core 5 and SQLite: Join table of Many-To-Many is not being cleared when deleting

The join table of a many-to-many relationship in my Xamarin.Forms application seems to not be cleared correctly when deleting one of the two entities.
I have these classes:
public class Input
{
// One-to-many
public ObservableCollection<InputResult> InputResults { get; set; }
//...
// Here are many more entities which shouldn't be relevant for this example
//...
}
public class InputResult
{
// One-to-many
public string ParentInputId { get; set;}
// Many-to-many
public ObservableCollection<MyDropdown> MyDropdowns { get; set; }
}
public class MyDropdown
{
// Many-to-many
public ObservableCollection<InputResult> InputResults { get; set; }
}
I configured the relationships in my DbContext class like this:
modelBuilder.Entity<Input>()
.HasMany(b => b.InputResults)
.WithOne()
.HasForeignKey(b => b.ParentInputId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<InputResult>()
.HasMany(b => b.MyDropdowns)
.WithMany(b => b.InputResults);
Let's say I have previously loaded an Input with its InputResults. Then I delete the InputResults in a helper class like that:
Context.RemoveRange(Input.InputResults);
The InputResults get deleted correctly. When I look into the SQLite database directly I still see all the entries in the join table of InputResults and MyDropdown. Why are there still entries? Yesterday one of our users got a unique constraint error after deleting some data and trying to insert the same data again.
I appreciate any help.
Edit:
To expand my comment on CSharp's answer:
I can't use OnDelete(DeleteBehavior.Cascade) when configuring the DbContext. It seems as EF Core did this correctly by itself though. The part of the join table in the DatabaseContextModelSnapshot.cs looks like this:
modelBuilder.Entity("InputResultMyDropdown", b =>
{
b.HasOne("Inputs.MyDropdown", null)
.WithMany()
.HasForeignKey("MyDropdownId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Inputs.InputResult", null)
.WithMany()
.HasForeignKey("InputResultId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
There should be a cascade delete behavior in DbContext:
modelBuilder.Entity<InputResult>()
.HasMany(b => b.MyDropdowns)
.WithMany(b => b.InputResults)
.OnDelete(DeleteBehavior.Cascade);

How to properly use EF Core to not create new junction table for every derived type?

I am currently having an inheritance structure in EntityFrameworkCore which looks like this:
Product as Base class
Underneath this product there can be a number of products. For example a CellPhone.
This CellPhone is sold in numberous shops. Let's call this junction table: cellphone_shop.
public class CellPhoneShop {
public int CellPhoneId;
public CellPhone CellPhone;
public int ShopId;
public Shop Shop;
}
In Entity Framework Core I expect to put something like:
modelBuilder.Entity<CellPhoneShop>()
.HasOne(x => x.CellPhone)
.WithMany(x => x.CellPhoneShops)
.HasForeignKey(x => x.CellPhoneId);
modelBuilder.Entity<CellPhoneShop>()
.HasOne(x => x.Shop)
.WithMany(x => x.CellPhoneShops)
.HasForeignKey(x => x.ShopId);
But imagine the situation that there are two other products. A Laptop and an iPad.
The Laptop is also sold in numberous shops, the iPad is NOT.
How is it possible to create one junction table ProductShop using Entity framework core?
I started like this:
public class ProductShop {
public int ProductId;
public Product Product;
public int ShopId;
public Shop Shop;
}
With the following EF mapping:
modelBuilder.Entity<ProductShop>()
.HasOne(x => x.Shop)
.WithMany(x => x.ProductShops)
.HasForeignKey(x => x.ShopId);
modelBuilder.Entity<ProductShop>()
.HasOne(x => x.Product)
.WithMany(??????????)
.HasForeignKey(x => x.ProductId);
The 'WithMany' property cannot be populated by a 'x.ProductShops' since only the derived members Laptop and CellPhone consist of shops.
Thanks for the help.
The solution was to create a different junction table for every derived type. In hibernate it would do this automatically, in EF Core (3.0) you are still obliged to do this yourself.

Entity Framework One-To-Many with only one navigation property: WithRequiredDependant?

Using the newest Entity Framework I have a class with a one-to-many wit only one navigation property on the many side.
As stated in MSDN: Entity Framework Fluent API - Relationships:
A one-directional (also called unidirectional) relationship is when a
navigation property is defined on only one of the relationship ends
and not on both.
Simplified: a School has many Students; there is a one-to-many relation between School and Student, but the School doesn't have a property containing the collection of Students
class Student
{
public int Id {get; set;}
// a Student attends one School; foreign key SchoolId
public int SchoolId {get; set;}
public School School {get; set;}
}
class School
{
public int Id {get; set;}
// missing: public virtual ICollection<Studen> Students {get; set;}
}
In a two-directional relationship, you could write the following fluent API in OnModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.HasRequired(student => student.School)
.WithMany(school => school.Students)
.HasForeignKey(student => student.SchoolId);
}
Because of the lack of School.Students, I need to do something extra. According to the link at the beginning it seems that I'd have to do something with WithRequiredDependant.
// Summary:
// Configures the relationship to be required without a navigation property
// on the other side of the relationship. The entity type being configured will
// be the dependent and contain a foreign key to the principal. The entity type
// that the relationship targets will be the principal in the relationship.
//
public ForeignKeyNavigationPropertyConfiguration WithRequiredDependent();
modelBuilder.Entity<Student>()
.HasRequired(student => student.School)
.WithRequiredDependent();
Alas, this doesn't work. SchoolId is not modeled as the foreign key.
What fluent API do I need?
I hope I have the right version/edition in mind:
modelBuilder.Entity<Student>()
.HasRequired(student => student.School)
//.WithMany(school => school.Students)
.WithMany()
.HasForeignKey(student => student.SchoolId);

How to configure EF6 multiple indepdendent code-first 1:1 unidirectional mappings?

I would like to configure two entities to have independent unidirectional 1:1 mappings using Code First Fluent API. But I am struggling to get the correct configuration (even though my schema looks right).
Models;
class User {
Guid Id;
virtual Subscription ActiveSubscription;
}
class Subscription {
Guid Id;
virtual User Owner;
}
In this relationship, Subscription.Owner should be NOT NULL but User.ActiveSubscription should be NULLABLE.
There can be many Subscription for the same User, with 0..1 of those referenced as the User.ActiveSubscription.
I'm using the following EntityTypeConfiguration implementations, but I am unable to INSERT both objects.
class UserMap : EntityTypeConfiguration<User> {
HasOptional(x => x.ActiveSubscription)
.WithOptionalDependent()
.Map(m => m.MapKey("ActiveSubscription_Id"))
.WillCascadeOnDelete(false);
}
class SubscriptionMap : {
HasRequired(x => x.Owner)
.WithOptional()
.Map(m => m.MapKey("Owner_Id"))
.WillCascadeOnDelete(true);
}
Deleting a User should CASCADE DELETE to Subscription table, though this should not be the case for the inverse relationship.
After generating a schema from this mapping, it looks correct, but I get errors on INSERT ("Unable to determine a valid ordering for dependent operations.")

How can I add additional field in N to N junction table in entity framework

I have two tables Group and 'User'. User can join to many groups. So I created this two objects and join them in fluent api:
public class Group
{...
public virtual ICollection<ApplicationUser> Members { get; set; }
and:
public class ApplicationUser
{...
public virtual ICollection<Group> MemberInGroups { get; set; }
And I mapped them in fluent api:
modelBuilder.Entity<Group>()
.HasMany(c => c.Members)
.WithMany(x => x.MemberInGroups)
.Map(a =>
{
a.ToTable("UsersInGroups");
a.MapLeftKey("GroupId");
a.MapRightKey("UserId");
});
How I can add here one more column in junction table like JoinDate?
EF doesn't support it. If you need a junction table with extra columns, that table must be mapped to an entity itself, and you lose the direct many-to-many navigation.
You'll have two many-to-one and one-to-many relationships instead, and you'll need to give two hops two navigate between then, i.e from an enttity to the junction table entity (which will be its child) and from the junction table entity to the collection of related entities of the other side of the relationship.
See this SO Q&A:
Many to many mapping with extra fields in Fluent API

Categories