Many to Many Self Reference - c#

An user can manage many company. And an user can have an active company at a time from list of many-company. How I can achieve this?
My current model is :
public class User
{
public int Id
public virtual ICollection<Company> Companies { get; set; }
public User()
{
this.Companies = new HashSet<Company>();
}
}
public class Company
{
public int Id
public virtual ICollection<User> Users { get; set; }
public User()
{
this.Users = new HashSet<User>();
}
}
If I add another anotation :
public class User
{
public int CompanyId
public virtual Company Company { get; set; }
}
This model wont referenced to many-to-many table which UserCompany table.
How I can achieve this? Or is there another approach for this case?
Now I'm thinking about make manual many-to-many relationship model and add another ActiveCompany field referenced from custom many-to-many relationship. Is this good approach?

I'm pretty sure you can do this by using the fluent api and overriding the OnModelCreating method in your DbContext, but I don't have an example to hand.
However you might just find it easier to add another property for your user
public int ActiveCompanyId { get; set; }
There are a lot of variables like if you are using lazy loading, how many companies / users there are, what your patterns of data access are, which may determine your best overall approach. If your Companies property is usually or always populated then you could create a get only property that is not mapped:
public class User
{
public int Id
public virtual ICollection<Company> Companies { get; set; }
public int ActiveCompanyId { get; set; }
[NotMapped]
public Company ActiveCompany
{
get
{
return this.Companys == null ? null :
Companies.Where(x => x.Id == this.Active.CompanyId)
.SingleOrDefault;
}
}
public User()
{
this.Companies = new HashSet<Company>();
}
}

Can you try this mapping :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Company>()
.HasMany(c => c.Users)
.WithMany(u => u.Comapnies)
.Map(x =>
{
x.MapLeftKey("CompanyId");
x.MapRightKey("UserId");
x.ToTable("UserCompany");
});
modelBuilder.Entity<User>()
.HasRequired(b => b.Company)
.WithMany()
.WillCascadeOnDelete(false);
}

Related

Entity Framework core multiple foreign keys same table error

i have looked at a ton of previous posts on how to have multiple foreign keys from the same table but I cant seem to get it working, even though my code seems identical to these posts. As far as I can tell, the below should work.
My User model
public string Name{get;set;}
public ICollection<UserOwnership> Slaves { get; set; } //Users this user owns
public ICollection<UserOwnership> Masters { get; set; } //Users that own this user
My user ownership model
public class UserOwnership
{
public int Id { get; set; }
public int MasterUserId { get; set; }
public int SlaveUserId { get; set; }
public virtual User Master { get; set; }
public virtual User Slave { get; set; }
}
UserOwnership mapping
public class UserOwnershipMapping : IEntityTypeConfiguration<UserOwnership>
{
public void Configure(EntityTypeBuilder<UserOwnership> builder)
{
builder.ToTable("UserOwnership");
builder.HasKey(e => new { e.Id });
builder.HasOne(e => e.Master).WithMany(e => e.Slaves).HasForeignKey(e => e.MasterUserId).OnDelete(DeleteBehavior.Restrict); // one master many slaves
builder.HasOne(e => e.Slave).WithMany(e => e.Masters).HasForeignKey(e => e.SlaveUserId).OnDelete(DeleteBehavior.Restrict); // one slave many masters
}
}
my error:
Unable to determine the relationship represented by navigation property 'User.Slaves' of type 'ICollection<UserOwnership>'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

Entity Framework retrieve objects based in condition

I am developing an Web Api application using Entity Framework where I have these two models and my DbContext class:
public class Course
{
[Key]
public int CourseId { get; set; }
[Required]
public string CourseName{ get; set; }
public ICollection<Students> Students { get; set; }
}
public class Students
{
[Key]
public int StudentId { get; set; }
[Required]
public string StudentName{ get; set; }
[Required]
public int StudentAge{ get; set; }
}
//My CourseContext
public class CourseContext : DbContext
{
public CourseContext () : base("CourseDB") { }
public DbSet<Course> Courses { get; set; }
public DbSet<Students> Students { get; set; }
}
I am modeling a WebAPi with these models above and I need to list all students that are taking a course which means that are added to the ICollection Students property in Course Class. I have tried to develop a solution for that but I have no idea how to do that since I do not have a foreign key property between the models.
...
using (var course_db = new CourseContext ()){
/*but this return all students and repeated ones since one student
can be in more than one course*/
var students= course_db.Course.Include("Students").Select(x=> x.Students);
if (students== null){
return Json(new { success = false });
}
return Json(students, JsonRequestBehavior.AllowGet);
}
...
I have tried the code below but it did not work. I just want to retrieve the students that are enrolled in a course, since some of them are not. Can someone help me?
You need to further build relationships in your model. The student to course relationship should be a many-to-many relationship which you are missing the proper properties in each but also a joining table and appropriate model builder (context) configuration.
Override your dbcontext model creation method to add your fluent configuration:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Build many-to-many relationships
modelBuilder.Entity<Student>()
.HasMany<Course>(c => c.Courses)
.WithMany(s => s.Student)
.Map(pe =>
{
pe.MapLeftKey("Student_ID");
pe.MapRightKey("Course_ID");
pe.ToTable("StudentCoursesTable");
});
}
Add missing Courses from your Student class:
public class Students
{
public ICollection<Courses> Courses { get; set; }
}

Mapping entity framework model to multiple tables

How can I map an entity framework model to multiple tables?
How to perform insertion operation to specific table (by reference of string which stores the table name)?
I have not implemented this but a quick search provides many good examples of a practice known as Entity Splitting. The following should be useful:
http://www.c-sharpcorner.com/UploadFile/ff2f08/entity-splitting-in-entity-framework-6-code-first-approach/
public partial class Employee
{
// These fields come from the “Employee” table
public int EmployeeId { get; set; }
public string Code { get; set; }
public string Name { get; set; }
// These fields come from the “EmployeeDetails” table
public string PhoneNumber { get; set; }
public string EmailAddress { get; set; }
}
public partial class Model : DbContext
{
public Model() : base("name=EntityModel")
{
Database.Log = Console.WriteLine;
}
public virtual DbSet<Employee> Employees { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>()
.Map(map =>
{
map.Properties(p => new
{
p.EmployeeId,
p.Name,
p.Code
});
map.ToTable("Employee");
})
// Map to the Users table
.Map(map =>
{
map.Properties(p => new
{
p.PhoneNumber,
p.EmailAddress
});
map.ToTable("EmployeeDetails");
});
}
}
All credit for the above code goes to linked post
In this case you can implement your own IModelCacheKeyFactory, which allow to hook into the model caching mechanism so EF is able to create different models based on some value right in runtime.
This article explains how

Entity Framework - How to map a required property on one side with no navigation property on other side

I have the following two POCOs (Product and User) and a complex type (Tracking).
class Product() {
Guid Id { get; protected set; }
Tracking TrackingInfo { get; protected set; }
// Some other properties
}
class User() {
Guid Id { get; protected set; }
// Some other properties
}
class Tracking() {
User CreatedBy { get; protected set; }
Guid CreatedById { get; protected set; }
// Some other properties
}
The tracking class is a wrapper for tracking info and contains other tracking properties (date created, updated etc) and fulfils an interface for other purposes, but for now what I am concerned with is mapping the relationships between the Product TrackingInfo and the User.
Every Product must have an associated User which maps to the TrackingInfo.CreatedBy property.
The catch is that I don't want to create navigation properties on the User back to the Product - i.e. I don't want to have an ICollection<Product> ProductsCreated property.
I'm not sure how the relationship or the complex type mapping should be done in EntityFramework Code First. I have a mapping class as follows:
public class ProductMap : EntityTypeConfiguration<Product>
{
public ProductMap()
{
this.Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("Id");
// Complex type mapping here?
}
}
How can I
Map the TrackingInfo complex type
Map the CreatedBy -> User single direction relationship?
Complex types cannot contain navigation properties. I recommend creating an abstract base class containing the Tracking properties as well as for its configuration:
public abstract class Tracking
{
public Guid CreatedById { get; set; }
public virtual User CreatedBy { get; set; }
}
public abstract class TrackingConfig<T> : EntityTypeConfiguration<T> where T: Tracking
{
public TrackingConfig()
{
HasRequired( t => t.CreatedBy )
.WithMany()
.HasForeignKey( t => t.CreatedById );
}
}
public class Product : Tracking
{
public Guid Id { get; set; }
}
public class ProductConfig : TrackingConfig<Product>
{
public ProductConfig()
{
}
}
...
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
base.OnModelCreating( modelBuilder );
modelBuilder.Configurations.Add( new ProductConfig() );
If you don't want the navigation properties, just don't define them:
public ProductMap()
{
this.HasRequired(p => p.Tracking)
.WithMany()
.HasForeignKey(p => p.TrackingId);
}
This way you will have access to the user of a product through Tracking, but you can't get the products from a user because there is no navigation property to Product defined in Tracking.

Entity, Many-To-Many, Add - Ignores Many to Many Table

I have this mapping:
modelBuilder.Entity<Reservation>()
.HasMany(e => e.Chairs)
.WithMany(e => e.Reservations)
.Map(m => m.ToTable("ReservationsChairs").MapLeftKey("Reservation_ID").MapRightKey("Chair_ID"));
So, the problem is when I try to create a reservation.
I have this Reservation Object:
public class Reservation
{
public Reservation()
{
Chairs = new HashSet<Chair>();
}
public int ID { get; set; }
public bool IsPaid { get; set; }
public virtual Planning Planning { get; set; }
public virtual ICollection<Chair> Chairs { get; set; }
}
I attach the chairs (Wich is already created), but, Entity does not use the Many-to-Many table, to bind the Reservation with the Chairs. It actually begins to create the same Chairs in the Chairs table...
Why does it do this, and what can I do to make it use the Many-To-Many?
My Chair Object has this:
public virtual ICollection<Reservation> Reservations { get; set; }
Above node will be "Null" when I create the Reservation, with the attached Chairs. Is that wrong?

Categories