Handling composite keys in db table - c#

I have a table called UsersInRoles with 2 X foreign keys as a composite key which doubles up as the primary key for this 2 column table. Just for resolving many-to-many. So within Entity Framework 6 I have the dal classes.
public partial class User
{
public User()
{
this.Roles = new HashSet<Role>();
}
public int UserId { get; set; }
public int ApplicationId { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public bool IsAnonymous { get; set; }
public System.DateTime LastActivityDate { get; set; }
public virtual Application Application { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
public partial class Role
{
public Role()
{
this.Users = new HashSet<User>();
}
public int RoleId { get; set; }
public int ApplicationId { get; set; }
public string RoleName { get; set; }
public string Description { get; set; }
public virtual Application Application { get; set; }
public virtual ICollection<User> Users { get; set; }
}
So I need to get at the fields within my composite table. I wondered if anyone can provide me with assistance on how to resolve this within OnModelCreating in the dbcontext. So that I can then do something with hasKeys

If you only need to change the Id's name or the table's name you can do that with this configuration:
modelBuilder.Entity<User>()
.HasMany(u => u.Roles)
.WithMany(r => r.Users)
.Map(cs =>
{
cs.MapLeftKey("UserRefId");
cs.MapRightKey("RoleRefId");
cs.ToTable("UsersInRoles");
});
Now if you need to get access explicitly to the junction table or you need to add it new columns, unfortunately you'll need to map it as part of your model.
public partial class User
{
public User()
{
this.Roles = new HashSet<Role>();
}
public int UserId { get; set; }
//...
public virtual ICollection<UsersInRoles> Roles { get; set; }
}
public partial class Role
{
public Role()
{
this.Users = new HashSet<User>();
}
public int RoleId { get; set; }
public virtual ICollection<UsersInRoles> Users { get; set; }
}
public class UsersInRoles
{
[Key, Column(Order = 0),ForeignKey("User")]
public int UserId { get; set; }
[Key, Column(Order = 1),ForeignKey("Role")]
public int RoleId { get; set; }
public virtual User User { get; set; }
public virtual Role Role { get; set; }
//add new properties here
}
If you prefer use Fluent Api, then remove the data annotations and add these configurations in the OnModelCreating method on your context:
modelBuilder.Entity<UsersInRoles>()
.HasKey(ur=> new { ur.UserId, ur.RoleId});
modelBuilder.Entity<UsersInRoles>()
.HasRequired(ur=> ur.User)
.WithMany(u => u.Roles)
.HasForeignKey(ur=> ur.UserId);
modelBuilder.Entity<UsersInRoles>()
.HasRequired(ur=> ur.Role)
.WithMany(u => u.Users)
.HasForeignKey(ur=> ur.RoleId);

Related

Foreign key is always 0 in relation one to one

In relation 1 - 1, I have two foreign keys in each of tabels that should tell me to what object I', referring. In table "WebAppUser" foreign key works correctly but in table "UserPermissions" I always get 0 as id of foreign key (column: "WebAppUserId" which is reference to a specific "WebAppUser").
My Code:
public class UserPermissions
{
[Key]
public int UserPermissionsId { get; set; }
//public int? WebAppUserId { get; set; }
public int WebAppUserId { get; set; }
public virtual WebAppUser WebAppUser { get; set; }
/*public virtual IEnumerable<WebAppUserClaims> Claims { get; set; }
public virtual IEnumerable<WebAppUserLogin> Logins { get; set; }
public virtual IEnumerable<WebAppUserToken> Tokens { get; set; }*/
public virtual IEnumerable<WebAppUserRole> WebAppUserRoles { get; set; }
}
public class WebAppUser /*: IdentityUser<int>*/
{
[Key]
public int Id { get; set; }
//1:1
public int UserProfileId { get; set; }
public virtual UserProfile UserProfile { get; set; }
//1:1
public int UserCredentialsId { get; set; }
public virtual UserCredential Credentials { get; set; }
//1:1
public int PermissionsId { get; set; }
public virtual UserPermissions UserPermissions { get; set; }
}
//WebAppUser - UserPermissions 1-1
modelBuilder.Entity<WebAppUser>()
.HasOne(x => x.UserPermissions)
.WithOne(y => y.WebAppUser)
.HasForeignKey<WebAppUser>(x => x.PermissionsId);
I tried entity configuration like this, but it also doesn't work:
modelBuilder.Entity<WebAppUser>()
.HasOne(x => x.UserPermissions)
.WithOne(y => y.WebAppUser)
.HasForeignKey<WebAppUser>(x => x.PermissionsId);
modelBuilder.Entity<UserPermissions>()
.HasOne(x => x.WebAppUser)
.WithOne(y => y.UserPermissions)
.HasForeignKey<UserPermissions>(x => x.WebAppUserId);```
Try this change in fluentApi
modelBuilder.Entity<WebAppUser>()
.HasOne<UserPermissions>(x => x.UserPermissions)
.WithOne(y => y.WebAppUser)
.HasForeignKey<UserPermissions>(x => x.WebAppUserId);
And don't forget when you make a request to this table to use Include(x => x.UserPermissions)

One foreign key in TPH model in EF Core

I have problem with my current model snapshot.
This is part of my model:
public class SalaryInfo
{
public Guid Id { get; set; }
public double SalaryRate { get; set; }
public string Description { get; set; }
public UserProfile UserProfile { get; set; }
public Guid UserProfileId { get; set; }
}
public class RoleBasedSalaryInfo : SalaryInfo
{
public Roles Role { get; set; }
}
public class UserProfile
{
public Guid Id { get; set; }
public Roles Role { get; set; }
public Account User { get; set; }
public Guid UserId { get; set; }
}
public class EmployeeProfile : UserProfile
{
public SalaryInfo OfferingInfo { get; set; }
}
public class LegalEntityProfile : UserProfile
{
public ICollection<RoleBasedSalaryInfo> HiringInfo { get; set; }
public bool IsLegalEntity { get; set; }
}
Roles and Account are not important in this case.
So, in my migration I have
modelBuilder.Entity<SalaryInfo>(builder =>
{
builder.HasDiscriminator<string>("Discriminator")
.HasValue<SalaryInfo>(nameof(SalaryInfo))
.HasValue<RoleBasedSalaryInfo>(nameof(RoleBasedSalaryInfo));
});
but in snapshot I get:
modelBuilder.Entity("EntityModel.Profiles.AuxiliaryClasses.EmployeeProfile", b =>
{
b.HasBaseType("EntityModel.Profiles.BaseProfiles.UserProfile");
b.Property<Guid?>("OfferingInfoId").HasColumnType("uniqueidentifier");
b.HasIndex("OfferingInfoId");
b.HasDiscriminator().HasValue(998);
});
modelBuilder.Entity("EntityModel.Profiles.AuxiliaryClasses.LegalEntityProfile", b =>
{
b.HasBaseType("EntityModel.Profiles.BaseProfiles.UserProfile");
b.Property<bool>("IsLegalEntity")
.HasColumnType("bit");
b.HasDiscriminator().HasValue(999);
});
modelBuilder.Entity("EntityModel.Profiles.AuxiliaryClasses.RoleBasedSalaryInfo", b =>
{
b.HasBaseType("EntityModel.Profiles.AuxiliaryClasses.SalaryInfo");
b.Property<Guid?>("LegalEntityProfileId")
.HasColumnType("uniqueidentifier");
b.Property<int>("Role")
.HasColumnType("int");
b.HasIndex("LegalEntityProfileId");
b.HasDiscriminator().HasValue("RoleBasedSalaryInfo");
});
modelBuilder.Entity("EntityModel.Profiles.AuxiliaryClasses.EmployeeProfile", b =>
{
b.HasOne("EntityModel.Profiles.AuxiliaryClasses.SalaryInfo", "OfferingInfo")
.WithMany()
.HasForeignKey("OfferingInfoId");
b.Navigation("OfferingInfo");
});
modelBuilder.Entity("EntityModel.Profiles.AuxiliaryClasses.RoleBasedSalaryInfo", b =>
{
b.HasOne("EntityModel.Profiles.AuxiliaryClasses.LegalEntityProfile", null)
.WithMany("HiringInfo")
.HasForeignKey("LegalEntityProfileId");
});
I really cannot understand of reason why LegalEntityProfileId and OfferingInfoId were added by migration. I supposed that I would get .HasForeighKey("UserProfileId") as a FK.
What should I do to get this "behaviour" (with UserProfileId as a FK)?
Thank you.

EF Code First Many-to-Many Relationship with ASP.NET Identity Table at one Side

I am trying to accomplish many-to-many relationship using code-first EF with ASP.NET Identity table at one side. The join table is not generated in the DB, though. What am I missing? Here are my model classes:
AppUser.cs:
public class AppUser : IdentityUser
{
public AppUser()
{
Notes = new HashSet<Note>();
}
public DateTime? LastSuccessfulLoginDate { get; set; }
public virtual ICollection<Note> Notes { get; set; }
}
and
Note.cs:
public class Note
{
public Note() {
NoteAssignedToUsers = new HashSet<AppUser>();
}
[Key]
public int NoteID { get; set; }
[Required]
public int FileID { get; set; }
[Required]
public string Content { get; set; }
[Required]
public Importance? Importance { get; set; }
[Required]
[DisplayFormat(DataFormatString = "{0:dd.MM.yyyy HH.mm}")]
public DateTime AddedOn { get; set; }
[Required]
public string CreatorID { get; set; }
[ForeignKey("FileID")]
public virtual OAFile OAFile { get; set; }
[ForeignKey("CreatorID")]
public virtual AppUser CreatedBy { get; set; }
public virtual ICollection<AppUser> NoteAssignedToUsers { get; set; }
}
In your dbcontext you can configure:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Note>()
.HasMany<AppUser>(s => s.NoteAssignedToUsers )
.WithMany(c => c.Notes)
.Map(cs =>
{
cs.MapLeftKey("AppUserId");
cs.MapRightKey("NoteId");
cs.ToTable("AppUsersNotes");
});
}

ASP.NET MVC customer portal User Junction Table

Im building a management portal for a chain of restaurants. I am using ASP.NET MVC with EF Code First.
I want each user to, after login, only see the rescources that are connected to them. I want to put a junction table(many-to-many) between ApplicationUser and the Restaurant-class(model), since each user can have/work at many restaurants, and each restaurant can have many owners/workers.
How do you do this in EF Code first? The same way I did Restaurant --> Menue? Do you need to build a new DBContext for Applicationuser for this to work?
public class Restaurant
{
public int Id { get; set; }
public string Name { get; set; }
public string Adress { get; set; }
public string PhoneNumber { get; set; }
public DateTime StartDate { get; set; }
//Connections
public virtual ICollection<Menue> Menues { get; set; }
}
public class Menue
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public DateTime ModifyDate { get; set; }
//FK For RestaurantConnection
public int RestaurantId { get; set; }
}
For many to many configuration do like this
Student class should have a collection navigation property for Course, and Course should have a collection navigation property for student
public class Student
{
public Student()
{
this.Courses = new HashSet<Course>();
}
public int StudentId { get; set; }
[Required]
public string StudentName { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
public class Course
{
public Course()
{
this.Students = new HashSet<Student>();
}
public int CourseId { get; set; }
public string CourseName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
In your DbContext add this configuration
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.HasMany<Course>(s => s.Courses)
.WithMany(c => c.Students)
.Map(cs =>
{
cs.MapLeftKey("StudentRefId");
cs.MapRightKey("CourseRefId");
cs.ToTable("StudentCourse");
});
}
For more information read this article Configure Many-to-Many relationship

EF Core 1.1 Many To Many Relation (ON DELETE NO ACTION or ON UPDATE NO ACTION)

I'm trying to create a model with a many-to-many relation:
A Company can have 0 or more Users
A Company can have 0 or more Roles
The many to many relation is between Users and Roles
Every time i try to create the database (update-database) I have the message:
Introducing FOREIGN KEY constraint 'FK_UsersRoles_Users_UserId' on table 'UsersRoles' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
and I don't understand what cycles it refers to. I mean, if I deleted a user it has to delete the entity inside UsersRoles and nothing more. The same if I delete a Role.
If my model has only Users and Roles, without the Company table, the database is created.
What am I doing wrong?
public class MyContext : DbContext
{
public DbSet<Company> Companies { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server = (localdb)\\mssqllocaldb; Database = ConsoleApp1; Trusted_Connection = True; MultipleActiveResultSets = true");
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserRole>()
.ToTable("UsersRoles")
.HasKey(t => new { t.UserId, t.RoleId });
modelBuilder.Entity<UserRole>()
.HasOne(pt => pt.User)
.WithMany(p => p.UsersRoles)
.HasForeignKey(pt => pt.UserId);
modelBuilder.Entity<UserRole>()
.HasOne(pt => pt.Role)
.WithMany(t => t.UsersRoles)
.HasForeignKey(pt => pt.RoleId);
base.OnModelCreating(modelBuilder);
}
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<User> Users { get; set; }
public ICollection<Role> Roles { get; set; }
}
public class User
{
public int Id { get; set; }
public string Surname { get; set; }
public int CompanyId { get; set; }
public Company Company { get; set; }
public ICollection<UserRole> UsersRoles { get; set; }
}
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
public int CompanyId { get; set; }
public Company Company { get; set; }
public ICollection<UserRole> UsersRoles { get; set; }
}
public class UserRole
{
public int UserId { get; set; }
public User User { get; set; }
public int RoleId { get; set; }
public Role Role { get; set; }
}

Categories

Resources